> + Send;
+}
diff --git a/crates/dictation/src/domain/service.rs b/crates/dictation/src/domain/service.rs
new file mode 100644
index 00000000000..94270c5ab61
--- /dev/null
+++ b/crates/dictation/src/domain/service.rs
@@ -0,0 +1,99 @@
+//! The transcription use case.
+
+use super::{
+ models::{DictationError, LanguageHint, MAX_AUDIO_DURATION, Recording, Transcript},
+ ports::{DictationService, RecordingInspector, TranscriptionProvider},
+};
+use ai_usage::{AiFeature, UsageContext, UsageRecorder};
+use bytes::Bytes;
+use macro_user_id::user_id::MacroUserIdStr;
+use std::{sync::Arc, time::Duration};
+use tokio::sync::Semaphore;
+
+/// Upper bound on in-flight inspections/provider requests per service process.
+const MAX_CONCURRENT_TRANSCRIPTIONS: usize = 16;
+/// Dictation for authenticated users on every plan.
+pub struct DictationServiceImpl {
+ provider: P,
+ inspector: I,
+ recorder: Arc,
+ capacity: Semaphore,
+}
+
+impl DictationServiceImpl {
+ /// Build a service with a bounded number of concurrent provider requests.
+ pub fn new(provider: P, inspector: I, recorder: Arc) -> Self {
+ Self {
+ provider,
+ inspector,
+ recorder,
+ capacity: Semaphore::new(MAX_CONCURRENT_TRANSCRIPTIONS),
+ }
+ }
+
+ #[cfg(test)]
+ pub(super) fn capacity(&self) -> &Semaphore {
+ &self.capacity
+ }
+}
+
+impl DictationService
+ for DictationServiceImpl
+{
+ #[tracing::instrument(name = "dictation.transcribe", skip_all, err, fields(
+ user_id = %user,
+ audio.bytes = audio.len(),
+ audio.format = tracing::field::Empty,
+ audio.duration_seconds = tracing::field::Empty,
+ dictation.stage = "validation",
+ dictation.in_flight = tracing::field::Empty,
+ ))]
+ async fn transcribe(
+ &self,
+ user: MacroUserIdStr<'static>,
+ audio: Bytes,
+ language: Option,
+ ) -> Result {
+ let span = tracing::Span::current();
+ let recording = Recording::new(audio, language)?;
+ span.record("audio.format", recording.format().extension());
+ span.record("dictation.stage", "admission");
+ let _permit = self.capacity.try_acquire().map_err(|_| {
+ tracing::warn!(
+ limit = MAX_CONCURRENT_TRANSCRIPTIONS,
+ "dictation capacity exhausted"
+ );
+ DictationError::Busy
+ })?;
+ span.record(
+ "dictation.in_flight",
+ MAX_CONCURRENT_TRANSCRIPTIONS - self.capacity.available_permits(),
+ );
+ span.record("dictation.stage", "inspection");
+ let duration = self.inspector.duration(recording.clone()).await?;
+ span.record("audio.duration_seconds", duration.as_secs_f64());
+ if duration.is_zero() {
+ return Err(DictationError::InvalidAudio);
+ }
+ if duration > MAX_AUDIO_DURATION {
+ return Err(DictationError::TooLong);
+ }
+ span.record("dictation.stage", "provider");
+ let transcript = self.provider.transcribe(recording).await?;
+ span.record("dictation.stage", "usage");
+ let duration = Duration::try_from_secs_f32(transcript.duration_seconds)
+ .map_err(|_| DictationError::Provider)?;
+ self.recorder.record(
+ UsageContext::new(AiFeature::Dictation, user)
+ .into_audio_event(self.provider.model_id().to_owned(), duration),
+ );
+ span.record("dictation.stage", "complete");
+ Ok(Transcript {
+ text: transcript.text.trim().to_owned(),
+ duration_seconds: transcript.duration_seconds,
+ })
+ }
+}
+
+#[cfg(test)]
+mod test;
diff --git a/crates/dictation/src/domain/service/test.rs b/crates/dictation/src/domain/service/test.rs
new file mode 100644
index 00000000000..9c27a3288b0
--- /dev/null
+++ b/crates/dictation/src/domain/service/test.rs
@@ -0,0 +1,270 @@
+use super::*;
+use crate::domain::models::{AudioFormat, MAX_AUDIO_BYTES};
+use std::sync::{
+ Arc, Mutex,
+ atomic::{AtomicUsize, Ordering},
+};
+use std::time::Duration;
+
+/// Minimal Ogg page header, as Firefox's MediaRecorder emits.
+const OGG_HEADER: &[u8] = b"OggS\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00";
+
+#[derive(Default)]
+struct FakeProvider {
+ fails: bool,
+ calls: AtomicUsize,
+ seen: Mutex)>>,
+}
+
+impl TranscriptionProvider for Arc {
+ fn model_id(&self) -> &'static str {
+ "whisper-1"
+ }
+
+ async fn transcribe(&self, recording: Recording) -> Result {
+ self.calls.fetch_add(1, Ordering::SeqCst);
+ if self.fails {
+ return Err(DictationError::Provider);
+ }
+ let (_, format, language) = recording.into_parts();
+ self.seen
+ .lock()
+ .unwrap()
+ .push((format, language.map(|hint| hint.to_string())));
+ Ok(Transcript {
+ text: " hello world ".into(),
+ duration_seconds: 2.0,
+ })
+ }
+}
+
+struct FakeInspector(Result);
+
+impl RecordingInspector for FakeInspector {
+ async fn duration(&self, _recording: Recording) -> Result {
+ match &self.0 {
+ Ok(duration) => Ok(*duration),
+ Err(_) => Err(DictationError::InvalidAudio),
+ }
+ }
+}
+
+fn service() -> (
+ DictationServiceImpl, FakeInspector>,
+ Arc,
+) {
+ let provider = Arc::new(FakeProvider::default());
+ (
+ DictationServiceImpl::new(
+ provider.clone(),
+ FakeInspector(Ok(Duration::from_secs(2))),
+ Arc::new(ai_usage::NoOpUsageRecorder),
+ ),
+ provider,
+ )
+}
+
+fn user() -> MacroUserIdStr<'static> {
+ MacroUserIdStr::try_from("macro|dictation-test@example.com".to_owned()).unwrap()
+}
+
+fn language() -> Option {
+ Some("en".parse().unwrap())
+}
+
+#[tokio::test]
+async fn transcribes_detected_audio_and_trims_text() {
+ let (service, provider) = service();
+ let transcript = service
+ .transcribe(user(), Bytes::from_static(OGG_HEADER), language())
+ .await
+ .unwrap();
+ assert_eq!(transcript.text, "hello world");
+ assert_eq!(transcript.duration_seconds, 2.0);
+ assert_eq!(provider.calls.load(Ordering::SeqCst), 1);
+ assert_eq!(
+ provider.seen.lock().unwrap().as_slice(),
+ [(AudioFormat::Ogg, Some("en".to_owned()))]
+ );
+}
+
+#[tokio::test]
+async fn rejects_empty_or_oversized_audio_before_calling_provider() {
+ let (service, provider) = service();
+ for bytes in [Bytes::new(), Bytes::from(vec![0; MAX_AUDIO_BYTES + 1])] {
+ assert_eq!(
+ service.transcribe(user(), bytes, language()).await,
+ Err(DictationError::InvalidSize)
+ );
+ }
+ assert_eq!(provider.calls.load(Ordering::SeqCst), 0);
+}
+
+#[tokio::test]
+async fn rejects_bytes_that_are_not_a_supported_audio_container() {
+ let (service, provider) = service();
+ for bytes in [
+ Bytes::from_static(b""),
+ Bytes::from_static(b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR"),
+ ] {
+ assert_eq!(
+ service.transcribe(user(), bytes, None).await,
+ Err(DictationError::UnsupportedAudio)
+ );
+ }
+ assert_eq!(provider.calls.load(Ordering::SeqCst), 0);
+}
+
+#[tokio::test]
+async fn capacity_guard_rejects_when_saturated_and_recovers() {
+ let (service, provider) = service();
+ let permits = service
+ .capacity()
+ .acquire_many(MAX_CONCURRENT_TRANSCRIPTIONS as u32)
+ .await
+ .unwrap();
+ assert_eq!(
+ service
+ .transcribe(user(), Bytes::from_static(OGG_HEADER), None)
+ .await,
+ Err(DictationError::Busy)
+ );
+ assert_eq!(provider.calls.load(Ordering::SeqCst), 0);
+ drop(permits);
+ assert!(
+ service
+ .transcribe(user(), Bytes::from_static(OGG_HEADER), None)
+ .await
+ .is_ok()
+ );
+}
+
+#[tokio::test]
+async fn rejects_invalid_and_long_audio_before_calling_the_provider() {
+ for (duration, expected) in [
+ (Ok(Duration::ZERO), DictationError::InvalidAudio),
+ (
+ Err(DictationError::InvalidAudio),
+ DictationError::InvalidAudio,
+ ),
+ (
+ Ok(MAX_AUDIO_DURATION + Duration::from_millis(1)),
+ DictationError::TooLong,
+ ),
+ ] {
+ let provider = Arc::new(FakeProvider::default());
+ let service = DictationServiceImpl::new(
+ provider.clone(),
+ FakeInspector(duration),
+ Arc::new(ai_usage::NoOpUsageRecorder),
+ );
+ assert_eq!(
+ service
+ .transcribe(user(), Bytes::from_static(OGG_HEADER), None)
+ .await,
+ Err(expected)
+ );
+ assert_eq!(provider.calls.load(Ordering::SeqCst), 0);
+ }
+}
+
+#[tokio::test]
+async fn accepts_the_exact_duration_limit() {
+ let provider = Arc::new(FakeProvider::default());
+ let service = DictationServiceImpl::new(
+ provider.clone(),
+ FakeInspector(Ok(MAX_AUDIO_DURATION)),
+ Arc::new(ai_usage::NoOpUsageRecorder),
+ );
+ assert!(
+ service
+ .transcribe(user(), Bytes::from_static(OGG_HEADER), None)
+ .await
+ .is_ok()
+ );
+ assert_eq!(provider.calls.load(Ordering::SeqCst), 1);
+}
+
+#[test]
+fn language_hint_accepts_only_two_lowercase_letters() {
+ assert_eq!("en".parse::().unwrap().as_str(), "en");
+ for invalid in ["EN", "en-US", "e", "", "1a"] {
+ assert_eq!(
+ invalid.parse::(),
+ Err(DictationError::InvalidLanguage)
+ );
+ }
+}
+
+#[test]
+fn detects_browser_containers_and_names_upload_by_extension() {
+ let webm = [
+ 0x1A, 0x45, 0xDF, 0xA3, 0x9F, 0x42, 0x86, 0x81, 0x01, 0x42, 0xF7, 0x81,
+ ];
+ let mp4 = b"\x00\x00\x00\x1cftypiso5\x00\x00\x02\x00isomiso5";
+ let wav = b"RIFF\x24\x00\x00\x00WAVEfmt ";
+ let mut ogg_opus = OGG_HEADER.to_vec();
+ ogg_opus.resize(28, 0);
+ ogg_opus.extend_from_slice(b"OpusHead\x01\x02");
+ for (bytes, format) in [
+ (&webm[..], AudioFormat::Webm),
+ (&mp4[..], AudioFormat::Mp4),
+ (&wav[..], AudioFormat::Wav),
+ (OGG_HEADER, AudioFormat::Ogg),
+ (&ogg_opus[..], AudioFormat::Ogg),
+ ] {
+ assert_eq!(AudioFormat::detect(bytes), Ok(format), "{format:?}");
+ }
+ assert_eq!(AudioFormat::Ogg.filename(), "dictation.ogg");
+ assert_eq!(
+ AudioFormat::detect(b"ID3\x03\x00\x00\x00"),
+ Err(DictationError::UnsupportedAudio),
+ "mp3 uploads are not produced by browser recorders"
+ );
+}
+
+#[derive(Default)]
+struct FakeRecorder(Mutex>);
+
+impl UsageRecorder for FakeRecorder {
+ fn record(&self, event: ai_usage::UsageEvent) {
+ self.0.lock().unwrap().push(event);
+ }
+}
+
+#[tokio::test]
+async fn records_provider_duration_only_for_successful_transcriptions() {
+ let recorder = Arc::new(FakeRecorder::default());
+ for fails in [false, true] {
+ let provider = Arc::new(FakeProvider {
+ fails,
+ ..FakeProvider::default()
+ });
+ let service = DictationServiceImpl::new(
+ provider,
+ FakeInspector(Ok(Duration::from_secs(3))),
+ recorder.clone(),
+ );
+ let result = service
+ .transcribe(user(), Bytes::from_static(OGG_HEADER), None)
+ .await;
+ assert_eq!(result.is_err(), fails);
+ assert!(
+ service
+ .transcribe(user(), Bytes::new(), None)
+ .await
+ .is_err()
+ );
+ }
+ let events = recorder.0.lock().unwrap();
+ assert_eq!(events.len(), 1);
+ assert_eq!(events[0].user, user());
+ assert_eq!(events[0].feature, AiFeature::Dictation);
+ assert_eq!(events[0].model, "whisper-1");
+ assert_eq!(
+ events[0].amount,
+ ai_usage::UsageAmount::Audio {
+ duration: Duration::from_secs(2)
+ }
+ );
+}
diff --git a/crates/dictation/src/inbound.rs b/crates/dictation/src/inbound.rs
new file mode 100644
index 00000000000..caa6e347fe5
--- /dev/null
+++ b/crates/dictation/src/inbound.rs
@@ -0,0 +1,3 @@
+//! Inbound adapters that drive the dictation use case.
+
+pub mod axum_router;
diff --git a/crates/dictation/src/inbound/axum_router.rs b/crates/dictation/src/inbound/axum_router.rs
new file mode 100644
index 00000000000..2fd9e997990
--- /dev/null
+++ b/crates/dictation/src/inbound/axum_router.rs
@@ -0,0 +1,281 @@
+//! Authenticated HTTP endpoint for dictation.
+//!
+//! The adapter only extracts identity, syntax-validates the request, and maps
+//! domain errors to status codes. Recording validation and provider policy live
+//! in the domain service.
+
+use crate::domain::{DictationError, DictationService, LanguageHint, MAX_AUDIO_BYTES, Transcript};
+use axum::{
+ Json, RequestPartsExt, Router,
+ body::Bytes,
+ extract::{DefaultBodyLimit, FromRef, FromRequestParts, Query, State},
+ http::{StatusCode, header},
+ response::{IntoResponse, Response},
+ routing::post,
+};
+use axum_extra::extract::Cached;
+use macro_authorization::{
+ MacroAuthorizationExtractor, MacroAuthorizationService, MacroAuthorizationState, UserOnly,
+};
+use model_error_response::ErrorResponse;
+use rate_limit::{
+ RateLimitConfig, RateLimitKey, RateLimitResult, RateLimitService,
+ domain::models::RateLimitOk,
+ inbound::{RateLimitExtractable, RateLimitExtractor},
+};
+use rootcause::Report;
+use serde::{Deserialize, Serialize};
+use std::{sync::Arc, time::Duration};
+
+/// Authenticated attempts per hour, including provider failures and retries.
+const PER_USER_TRANSCRIPTIONS_PER_HOUR: u64 = 60;
+
+/// State for the dictation router.
+pub struct DictationRouterState {
+ service: Arc,
+ rate_limiter: R,
+ authorization_state: MacroAuthorizationState,
+}
+
+impl Clone for DictationRouterState {
+ fn clone(&self) -> Self {
+ Self {
+ service: self.service.clone(),
+ rate_limiter: self.rate_limiter.clone(),
+ authorization_state: self.authorization_state.clone(),
+ }
+ }
+}
+
+impl DictationRouterState {
+ /// Create dictation router state.
+ pub fn new(
+ service: S,
+ rate_limiter: R,
+ authorization_state: MacroAuthorizationState,
+ ) -> Self {
+ Self {
+ service: Arc::new(service),
+ rate_limiter,
+ authorization_state,
+ }
+ }
+}
+
+impl FromRef> for Arc {
+ fn from_ref(state: &DictationRouterState) -> Self {
+ state.service.clone()
+ }
+}
+
+impl FromRef> for MacroAuthorizationState {
+ fn from_ref(state: &DictationRouterState) -> Self {
+ state.authorization_state.clone()
+ }
+}
+
+impl RateLimitService for DictationRouterState
+where
+ S: Send + Sync + 'static,
+ R: RateLimitService,
+ Auth: MacroAuthorizationService,
+{
+ async fn check_rate_limit(
+ &self,
+ key: RateLimitKey,
+ config: RateLimitConfig,
+ ) -> Result {
+ let limit = config.max_count;
+ let window_seconds = config.window.as_secs();
+ let result = self.rate_limiter.check_rate_limit(key, config).await?;
+ if result.is_err() {
+ tracing::warn!(limit, window_seconds, "dictation rate limit exceeded");
+ }
+ Ok(result)
+ }
+
+ async fn rollback_ticket(&self, ticket: RateLimitOk) -> Result<(), Report> {
+ self.rate_limiter.rollback_ticket(ticket).await
+ }
+}
+
+/// Per-user transcription rate limit. Only signed-in users may dictate; bots,
+/// harnesses, and internal callers are rejected by the `UserOnly` policy.
+pub struct PerUserDictationRateLimit(MacroAuthorizationExtractor);
+
+impl RateLimitExtractable for PerUserDictationRateLimit
+where
+ S: Send + Sync + 'static,
+ Auth: MacroAuthorizationService,
+ MacroAuthorizationState: FromRef,
+{
+ fn config() -> RateLimitConfig {
+ RateLimitConfig {
+ max_count: PER_USER_TRANSCRIPTIONS_PER_HOUR,
+ window: Duration::from_secs(3600),
+ }
+ }
+
+ fn key(&self) -> RateLimitKey {
+ RateLimitKey::builder(&"per-user-dictation")
+ .append(&self.0.authorization.macro_user_id.as_ref())
+ .finish()
+ }
+}
+
+impl FromRequestParts for PerUserDictationRateLimit
+where
+ S: Send + Sync + 'static,
+ Auth: MacroAuthorizationService,
+ MacroAuthorizationState: FromRef,
+{
+ type Rejection = Response;
+
+ async fn from_request_parts(
+ parts: &mut axum::http::request::Parts,
+ state: &S,
+ ) -> Result {
+ let Cached(authorization): Cached> = parts
+ .extract_with_state(state)
+ .await
+ .map_err(IntoResponse::into_response)?;
+ // This runs before the body is buffered and before rate-limit rejection.
+ tracing::Span::current().record(
+ "user_id",
+ authorization.authorization.macro_user_id.as_ref(),
+ );
+ Ok(Self(authorization))
+ }
+}
+
+/// Create the dictation router. Mount under `/dictation`.
+pub fn dictation_router(state: DictationRouterState) -> Router
+where
+ S: DictationService,
+ R: RateLimitService + Clone,
+ Auth: MacroAuthorizationService,
+ T: Send + Sync + 'static,
+{
+ Router::new()
+ .route("/transcribe", post(transcribe_handler::))
+ .layer(DefaultBodyLimit::max(MAX_AUDIO_BYTES))
+ .layer(axum::middleware::from_fn(trace_request))
+ .with_state(state)
+}
+
+/// Covers extractor failures as well as the handler, under the shared HTTP span.
+#[tracing::instrument(name = "dictation.request", skip_all, fields(
+ user_id = tracing::field::Empty,
+ http.response.status_code = tracing::field::Empty,
+))]
+async fn trace_request(request: axum::extract::Request, next: axum::middleware::Next) -> Response {
+ let response = next.run(request).await;
+ tracing::Span::current().record("http.response.status_code", response.status().as_u16());
+ response
+}
+
+/// Query parameters for transcription.
+#[derive(Debug, Deserialize)]
+pub struct TranscribeQuery {
+ /// Optional ISO 639-1 recognition hint.
+ pub language: Option,
+}
+
+/// Transcription result.
+#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
+pub struct TranscribeResponse {
+ /// Recognized text.
+ pub text: String,
+}
+
+impl From for TranscribeResponse {
+ fn from(transcript: Transcript) -> Self {
+ Self {
+ text: transcript.text,
+ }
+ }
+}
+
+/// OpenAPI representation of the raw encoded audio body extracted as `Bytes`.
+#[derive(utoipa::ToSchema)]
+#[schema(value_type = String, format = Binary)]
+pub struct EncodedAudioBody(
+ /// Browser-encoded audio bytes.
+ pub Vec,
+);
+
+/// Transcribe a transient recording with OpenAI Whisper.
+///
+/// Available to every signed-in user on every plan; does not consume chat
+/// credits. Audio and transcripts are never persisted.
+#[utoipa::path(
+ post,
+ tag = "dictation",
+ operation_id = "transcribe_dictation",
+ path = "/dictation/transcribe",
+ params(("language" = Option, Query, description = "ISO 639-1 language hint")),
+ request_body(content = inline(EncodedAudioBody), content_type = "audio/webm", description = "Encoded WebM, MP4, Ogg, or WAV audio up to 8 MiB and five minutes"),
+ responses(
+ (status = 200, body = TranscribeResponse),
+ (status = 400, description = "Empty, oversized, or malformed request", body = ErrorResponse),
+ (status = 401, description = "Missing or invalid credentials", body = ErrorResponse),
+ (status = 403, description = "Only signed-in users may dictate", body = ErrorResponse),
+ (status = 413, description = "Body exceeds 8 MiB"),
+ (status = 415, description = "Unsupported audio container", body = ErrorResponse),
+ (status = 429, description = "Per-user hourly rate limit exceeded"),
+ (status = 502, description = "Provider failure", body = ErrorResponse),
+ (status = 503, description = "Transcription capacity exhausted; retry after the Retry-After delay", body = ErrorResponse),
+ )
+)]
+pub async fn transcribe_handler(
+ Cached(user): Cached>,
+ _limit: RateLimitExtractor, DictationRouterState>,
+ State(service): State>,
+ Query(query): Query,
+ audio: Bytes,
+) -> Result, DictationError>
+where
+ S: DictationService,
+ R: RateLimitService + Clone,
+ Auth: MacroAuthorizationService,
+{
+ let language = query
+ .language
+ .as_deref()
+ .map(str::parse::)
+ .transpose()
+ .inspect_err(|error| tracing::warn!(error = ?error, "invalid dictation language hint"))?;
+ let transcript = service
+ .transcribe(user.authorization.macro_user_id, audio, language)
+ .await?;
+ Ok(Json(transcript.into()))
+}
+
+impl IntoResponse for DictationError {
+ fn into_response(self) -> Response {
+ let status = match self {
+ Self::InvalidSize | Self::InvalidLanguage | Self::InvalidAudio | Self::TooLong => {
+ StatusCode::BAD_REQUEST
+ }
+ Self::UnsupportedAudio => StatusCode::UNSUPPORTED_MEDIA_TYPE,
+ Self::Busy => StatusCode::SERVICE_UNAVAILABLE,
+ Self::Provider => StatusCode::BAD_GATEWAY,
+ };
+ let mut response = (
+ status,
+ Json(ErrorResponse {
+ message: self.to_string().into(),
+ }),
+ )
+ .into_response();
+ if matches!(self, Self::Busy) {
+ response
+ .headers_mut()
+ .insert(header::RETRY_AFTER, header::HeaderValue::from_static("1"));
+ }
+ response
+ }
+}
+
+#[cfg(test)]
+mod test;
diff --git a/crates/dictation/src/inbound/axum_router/test.rs b/crates/dictation/src/inbound/axum_router/test.rs
new file mode 100644
index 00000000000..1829361d2df
--- /dev/null
+++ b/crates/dictation/src/inbound/axum_router/test.rs
@@ -0,0 +1,330 @@
+use super::*;
+use crate::domain::{DictationError, Transcript};
+use axum::{
+ body::{Body, to_bytes},
+ http::{Request, header},
+};
+use bytes::Bytes;
+use macro_authorization::{InternalIdentityClaims, MacroAuthorizationError};
+use macro_user_id::user_id::MacroUserIdStr;
+use model_user::UserContext;
+use rate_limit::domain::models::RateLimitOk;
+use std::sync::{
+ Arc, Mutex,
+ atomic::{AtomicUsize, Ordering},
+};
+use tower::ServiceExt;
+
+const USER_ID: &str = "macro|dictation-test@example.com";
+const INTERNAL_KEY: &str = "valid-internal-key";
+
+/// `(user id, audio bytes, language hint)` as seen by the service.
+type ServiceCall = (String, usize, Option);
+
+#[derive(Clone, Default)]
+struct FakeService {
+ calls: Arc>>,
+ response: Arc>>>,
+}
+
+impl FakeService {
+ fn respond(&self, response: Result) {
+ *self.response.lock().unwrap() = Some(response);
+ }
+
+ fn calls(&self) -> Vec {
+ self.calls.lock().unwrap().clone()
+ }
+}
+
+impl DictationService for FakeService {
+ async fn transcribe(
+ &self,
+ user: MacroUserIdStr<'static>,
+ audio: Bytes,
+ language: Option,
+ ) -> Result {
+ self.calls.lock().unwrap().push((
+ user.to_string(),
+ audio.len(),
+ language.map(|hint| hint.to_string()),
+ ));
+ self.response.lock().unwrap().take().unwrap_or_else(|| {
+ Ok(Transcript {
+ text: "hello".into(),
+ duration_seconds: 1.0,
+ })
+ })
+ }
+}
+
+#[derive(Clone, Default)]
+struct FakeRateLimiter {
+ exceeded: bool,
+ checks: Arc,
+ rollbacks: Arc,
+}
+
+impl RateLimitService for FakeRateLimiter {
+ async fn check_rate_limit(
+ &self,
+ key: RateLimitKey,
+ config: RateLimitConfig,
+ ) -> Result {
+ self.checks.fetch_add(1, Ordering::SeqCst);
+ if self.exceeded {
+ return Ok(Err(rate_limit::RateLimitExceeded {
+ current_count: config.max_count,
+ max_count: config.max_count,
+ retry_after: config.window,
+ }));
+ }
+ Ok(Ok(RateLimitOk::new_testing_value(1, key, config)))
+ }
+
+ async fn rollback_ticket(&self, _ticket: RateLimitOk) -> Result<(), Report> {
+ self.rollbacks.fetch_add(1, Ordering::SeqCst);
+ Ok(())
+ }
+}
+
+#[derive(Clone, Default)]
+struct FakeAuthorizationService;
+
+impl MacroAuthorizationService for FakeAuthorizationService {
+ async fn authorize(&self, jwt: &str) -> Result> {
+ if jwt != "valid" {
+ return Err(Report::new(MacroAuthorizationError::InvalidCredentials));
+ }
+ Ok(UserContext {
+ user_id: USER_ID.to_owned(),
+ ..UserContext::default()
+ })
+ }
+
+ async fn authorize_internal(
+ &self,
+ provided_key: &str,
+ claims: InternalIdentityClaims,
+ ) -> Result, Report> {
+ if provided_key != INTERNAL_KEY {
+ return Err(Report::new(MacroAuthorizationError::InvalidCredentials));
+ }
+ Ok(claims.user_id.map(|user_id| UserContext {
+ user_id,
+ ..UserContext::default()
+ }))
+ }
+}
+
+struct Harness {
+ service: FakeService,
+ limiter: FakeRateLimiter,
+}
+
+impl Harness {
+ fn new() -> Self {
+ Self {
+ service: FakeService::default(),
+ limiter: FakeRateLimiter::default(),
+ }
+ }
+
+ fn rate_limited() -> Self {
+ Self {
+ limiter: FakeRateLimiter {
+ exceeded: true,
+ ..FakeRateLimiter::default()
+ },
+ ..Self::new()
+ }
+ }
+
+ fn router(&self) -> Router {
+ dictation_router::<_, _, _, ()>(DictationRouterState::new(
+ self.service.clone(),
+ self.limiter.clone(),
+ MacroAuthorizationState::new(Arc::new(FakeAuthorizationService)),
+ ))
+ }
+
+ async fn post(
+ &self,
+ uri: &str,
+ headers: &[(header::HeaderName, &str)],
+ body: impl Into,
+ ) -> Response {
+ let mut request = Request::builder().method("POST").uri(uri);
+ for (name, value) in headers {
+ request = request.header(name, *value);
+ }
+ self.router()
+ .oneshot(request.body(body.into()).unwrap())
+ .await
+ .unwrap()
+ }
+}
+
+async fn message(response: Response) -> String {
+ let bytes = to_bytes(response.into_body(), usize::MAX).await.unwrap();
+ serde_json::from_slice::(&bytes).unwrap()["message"]
+ .as_str()
+ .unwrap()
+ .to_owned()
+}
+
+#[tokio::test]
+async fn transcribes_for_an_authenticated_user_and_forwards_language() {
+ let harness = Harness::new();
+ let response = harness
+ .post(
+ "/transcribe?language=en",
+ &[(header::AUTHORIZATION, "Bearer valid")],
+ "OggS-bytes",
+ )
+ .await;
+
+ assert_eq!(response.status(), StatusCode::OK);
+ let bytes = to_bytes(response.into_body(), usize::MAX).await.unwrap();
+ let body: TranscribeResponse = serde_json::from_slice(&bytes).unwrap();
+ assert_eq!(body.text, "hello");
+ assert_eq!(
+ harness.service.calls(),
+ [(USER_ID.to_owned(), 10, Some("en".to_owned()))]
+ );
+ assert_eq!(harness.limiter.checks.load(Ordering::SeqCst), 1);
+ assert_eq!(harness.limiter.rollbacks.load(Ordering::SeqCst), 0);
+}
+
+#[tokio::test]
+async fn rejects_missing_and_invalid_credentials_before_any_work() {
+ let harness = Harness::new();
+ for headers in [&[][..], &[(header::AUTHORIZATION, "Bearer wrong")][..]] {
+ let response = harness.post("/transcribe", headers, "audio").await;
+ assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
+ }
+ assert!(harness.service.calls().is_empty());
+ assert_eq!(harness.limiter.checks.load(Ordering::SeqCst), 0);
+}
+
+#[tokio::test]
+async fn rejects_internal_callers_because_dictation_is_user_only() {
+ let harness = Harness::new();
+ let response = harness
+ .post(
+ "/transcribe",
+ &[
+ (
+ header::HeaderName::from_static("x-internal-auth-key"),
+ INTERNAL_KEY,
+ ),
+ (
+ header::HeaderName::from_static("x-internal-macro-user-id"),
+ USER_ID,
+ ),
+ ],
+ "audio",
+ )
+ .await;
+
+ assert_eq!(response.status(), StatusCode::FORBIDDEN);
+ assert!(harness.service.calls().is_empty());
+}
+
+#[tokio::test]
+async fn enforces_the_per_user_rate_limit() {
+ let harness = Harness::rate_limited();
+ let response = harness
+ .post(
+ "/transcribe",
+ &[(header::AUTHORIZATION, "Bearer valid")],
+ "audio",
+ )
+ .await;
+
+ assert_eq!(response.status(), StatusCode::TOO_MANY_REQUESTS);
+ assert!(harness.service.calls().is_empty());
+}
+
+#[tokio::test]
+async fn failed_provider_attempts_still_consume_the_rate_limit() {
+ let harness = Harness::new();
+ harness.service.respond(Err(DictationError::Provider));
+ let response = harness
+ .post(
+ "/transcribe",
+ &[(header::AUTHORIZATION, "Bearer valid")],
+ "audio",
+ )
+ .await;
+
+ assert_eq!(response.status(), StatusCode::BAD_GATEWAY);
+ assert_eq!(harness.limiter.checks.load(Ordering::SeqCst), 1);
+ assert_eq!(harness.limiter.rollbacks.load(Ordering::SeqCst), 0);
+}
+
+#[tokio::test]
+async fn maps_domain_errors_to_status_codes_without_leaking_content() {
+ let cases = [
+ (DictationError::InvalidSize, StatusCode::BAD_REQUEST),
+ (DictationError::InvalidAudio, StatusCode::BAD_REQUEST),
+ (DictationError::TooLong, StatusCode::BAD_REQUEST),
+ (
+ DictationError::UnsupportedAudio,
+ StatusCode::UNSUPPORTED_MEDIA_TYPE,
+ ),
+ (DictationError::Busy, StatusCode::SERVICE_UNAVAILABLE),
+ (DictationError::Provider, StatusCode::BAD_GATEWAY),
+ ];
+ for (error, status) in cases {
+ let harness = Harness::new();
+ let expected = error.to_string();
+ harness.service.respond(Err(error));
+ let response = harness
+ .post(
+ "/transcribe",
+ &[(header::AUTHORIZATION, "Bearer valid")],
+ "audio",
+ )
+ .await;
+ assert_eq!(response.status(), status);
+ assert_eq!(
+ response
+ .headers()
+ .get(header::RETRY_AFTER)
+ .map(|value| value.to_str().unwrap()),
+ (status == StatusCode::SERVICE_UNAVAILABLE).then_some("1")
+ );
+ assert_eq!(message(response).await, expected);
+ }
+}
+
+#[tokio::test]
+async fn rejects_a_malformed_language_hint_in_the_adapter() {
+ let harness = Harness::new();
+ let response = harness
+ .post(
+ "/transcribe?language=en-US",
+ &[(header::AUTHORIZATION, "Bearer valid")],
+ "audio",
+ )
+ .await;
+
+ assert_eq!(response.status(), StatusCode::BAD_REQUEST);
+ assert!(harness.service.calls().is_empty());
+}
+
+#[tokio::test]
+async fn rejects_bodies_over_the_recording_cap() {
+ let harness = Harness::new();
+ let response = harness
+ .post(
+ "/transcribe",
+ &[(header::AUTHORIZATION, "Bearer valid")],
+ vec![0u8; MAX_AUDIO_BYTES + 1],
+ )
+ .await;
+
+ assert_eq!(response.status(), StatusCode::PAYLOAD_TOO_LARGE);
+ assert!(harness.service.calls().is_empty());
+}
diff --git a/crates/dictation/src/lib.rs b/crates/dictation/src/lib.rs
new file mode 100644
index 00000000000..cd2299cf7ab
--- /dev/null
+++ b/crates/dictation/src/lib.rs
@@ -0,0 +1,12 @@
+//! Private, transient audio transcription for composer dictation.
+//!
+//! Hexagonal layout: [`domain`] owns recording validation, the provider port,
+//! and the use case; [`inbound`] exposes the authenticated, rate-limited HTTP
+//! endpoint; [`outbound`] implements the port with OpenAI Whisper.
+#![deny(missing_docs)]
+
+pub mod domain;
+#[cfg(feature = "inbound")]
+pub mod inbound;
+#[cfg(feature = "outbound")]
+pub mod outbound;
diff --git a/crates/dictation/src/outbound.rs b/crates/dictation/src/outbound.rs
new file mode 100644
index 00000000000..c27129d7513
--- /dev/null
+++ b/crates/dictation/src/outbound.rs
@@ -0,0 +1,7 @@
+//! Outbound adapters implementing the dictation ports.
+
+pub mod media;
+pub mod whisper;
+
+pub use media::SymphoniaRecordingInspector;
+pub use whisper::{OpenaiApiKey, WhisperTranscriber};
diff --git a/crates/dictation/src/outbound/media.rs b/crates/dictation/src/outbound/media.rs
new file mode 100644
index 00000000000..5ef8e409341
--- /dev/null
+++ b/crates/dictation/src/outbound/media.rs
@@ -0,0 +1,128 @@
+//! Inspect browser recording containers without transcoding or temporary files.
+
+use crate::domain::{AudioFormat, DictationError, Recording, RecordingInspector};
+use std::{
+ io::{Cursor, ErrorKind},
+ time::Duration,
+};
+use symphonia::core::{
+ codecs::{CodecParameters, audio::well_known::CODEC_ID_OPUS},
+ errors::Error,
+ formats::{FormatOptions, probe::Hint},
+ io::MediaSourceStream,
+ meta::MetadataOptions,
+};
+
+/// Symphonia demuxes WebM/Opus, MP4/AAC, Ogg/Opus, and WAV in memory.
+/// Reading packet timestamps does not require an Opus decoder or re-encoding.
+pub struct SymphoniaRecordingInspector;
+
+impl RecordingInspector for SymphoniaRecordingInspector {
+ #[tracing::instrument(name = "dictation.inspect_audio", skip_all, err, fields(
+ audio.format = recording.format().extension(),
+ audio.bytes = recording.bytes().len(),
+ ))]
+ async fn duration(&self, recording: Recording) -> Result {
+ // Container parsing is CPU work; it must not block the async executor.
+ // Blocking tasks do not inherit the request's tracing context.
+ let span = tracing::Span::current();
+ tokio::task::spawn_blocking(move || span.in_scope(|| inspect(recording)))
+ .await
+ .map_err(|error| {
+ tracing::error!(panicked = error.is_panic(), "audio inspection task failed");
+ DictationError::InvalidAudio
+ })?
+ }
+}
+
+#[tracing::instrument(name = "dictation.parse_audio", skip_all, err, fields(
+ audio.duration_seconds = tracing::field::Empty,
+ audio.packet_count = tracing::field::Empty,
+ dictation.inspection_stage = "probe",
+))]
+fn inspect(recording: Recording) -> Result {
+ let span = tracing::Span::current();
+ let mut hint = Hint::new();
+ hint.with_extension(recording.format().extension());
+ let (bytes, format, _) = recording.into_parts();
+ let source = MediaSourceStream::new(Box::new(Cursor::new(bytes)), Default::default());
+ let mut reader = symphonia::default::get_probe()
+ .probe(
+ &hint,
+ source,
+ FormatOptions::default(),
+ MetadataOptions::default(),
+ )
+ .map_err(|_| DictationError::InvalidAudio)?;
+ span.record("dictation.inspection_stage", "track");
+ let track = reader
+ .tracks()
+ .iter()
+ .find(|track| {
+ track
+ .codec_params
+ .as_ref()
+ .is_some_and(CodecParameters::is_audio)
+ })
+ .ok_or(DictationError::InvalidAudio)?;
+ let track_id = track.id;
+ let codec = track
+ .codec_params
+ .as_ref()
+ .and_then(CodecParameters::audio)
+ .ok_or(DictationError::InvalidAudio)?
+ .codec;
+ let time_base = track.time_base.ok_or(DictationError::InvalidAudio)?;
+ let mut end = 0.0_f64;
+ let mut first = None;
+ let mut packet_count = 0_u64;
+ span.record("dictation.inspection_stage", "packets");
+ loop {
+ let packet = match reader.next_packet() {
+ Ok(Some(packet)) => packet,
+ Ok(None) => break,
+ // MediaRecorder leaves its streaming WebM segment open at EOF.
+ Err(Error::IoError(error))
+ if format == AudioFormat::Webm && error.kind() == ErrorKind::UnexpectedEof =>
+ {
+ break;
+ }
+ Err(_) => return Err(DictationError::InvalidAudio),
+ };
+ if packet.track_id == track_id {
+ packet_count += 1;
+ let timestamp = time_base
+ .calc_time(packet.pts)
+ .ok_or(DictationError::InvalidAudio)?
+ .as_secs_f64();
+ // Chrome omits BlockDuration/DefaultDuration. Read Opus framing
+ // through the codec library; no decoding or handwritten bit parser.
+ let duration = if packet.dur.is_zero() && codec == CODEC_ID_OPUS {
+ let samples = opus_pure::packet::samples_48k(&packet.data)
+ .map_err(|_| DictationError::InvalidAudio)?;
+ samples as f64 / 48_000.0
+ } else {
+ time_base
+ .calc_duration(packet.dur)
+ .ok_or(DictationError::InvalidAudio)?
+ .as_secs_f64()
+ };
+ first.get_or_insert(timestamp);
+ end = end.max(timestamp + duration);
+ }
+ }
+ span.record("audio.packet_count", packet_count);
+ span.record("dictation.inspection_stage", "duration");
+ let seconds = end - first.ok_or(DictationError::InvalidAudio)?;
+ if seconds <= 0.0 {
+ return Err(DictationError::InvalidAudio);
+ }
+ let duration =
+ Duration::try_from_secs_f64(seconds).map_err(|_| DictationError::InvalidAudio)?;
+ span.record("audio.duration_seconds", duration.as_secs_f64());
+ span.record("dictation.inspection_stage", "complete");
+ Ok(duration)
+}
+
+#[cfg(test)]
+mod test;
diff --git a/crates/dictation/src/outbound/media/test.rs b/crates/dictation/src/outbound/media/test.rs
new file mode 100644
index 00000000000..ac24b65e4bd
--- /dev/null
+++ b/crates/dictation/src/outbound/media/test.rs
@@ -0,0 +1,65 @@
+use super::*;
+use bytes::Bytes;
+
+#[tokio::test]
+async fn inspects_real_browser_containers_without_decoding_or_transcoding() {
+ for bytes in [
+ include_bytes!("../../../tests/fixtures/tone.webm").as_slice(),
+ include_bytes!("../../../tests/fixtures/tone.ogg").as_slice(),
+ include_bytes!("../../../tests/fixtures/tone.mp4").as_slice(),
+ include_bytes!("../../../tests/fixtures/tone.wav").as_slice(),
+ ] {
+ let recording = Recording::new(Bytes::from_static(bytes), None).unwrap();
+ let format = recording.format();
+ let duration = SymphoniaRecordingInspector
+ .duration(recording)
+ .await
+ .unwrap();
+ // Codec framing/padding differs; each fixture contains 100 ms of audio.
+ assert!(
+ (0.09..0.25).contains(&duration.as_secs_f64()),
+ "{format:?}: {duration:?}"
+ );
+ }
+}
+
+#[tokio::test]
+async fn inspects_a_chrome_media_recorder_stream_without_container_duration() {
+ let recording = Recording::new(
+ Bytes::from_static(include_bytes!("../../../tests/fixtures/chrome.webm")),
+ None,
+ )
+ .unwrap();
+ let duration = SymphoniaRecordingInspector
+ .duration(recording)
+ .await
+ .unwrap();
+ assert_eq!(duration, Duration::from_millis(240));
+}
+
+#[tokio::test]
+async fn rejects_header_only_audio() {
+ let recording = Recording::new(
+ Bytes::from_static(b"OggS\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00"),
+ None,
+ )
+ .unwrap();
+ assert_eq!(
+ SymphoniaRecordingInspector.duration(recording).await,
+ Err(DictationError::InvalidAudio)
+ );
+}
+
+#[tokio::test]
+async fn identifies_long_compressed_audio_even_below_the_byte_limit() {
+ let recording = Recording::new(
+ Bytes::from_static(include_bytes!("../../../tests/fixtures/long.ogg")),
+ None,
+ )
+ .unwrap();
+ let duration = SymphoniaRecordingInspector
+ .duration(recording)
+ .await
+ .unwrap();
+ assert!(duration > crate::domain::MAX_AUDIO_DURATION);
+}
diff --git a/crates/dictation/src/outbound/whisper.rs b/crates/dictation/src/outbound/whisper.rs
new file mode 100644
index 00000000000..147ad17ff79
--- /dev/null
+++ b/crates/dictation/src/outbound/whisper.rs
@@ -0,0 +1,158 @@
+//! OpenAI Whisper adapter for the [`TranscriptionProvider`] port.
+//!
+//! `/v1/audio/transcriptions` is eligible for OpenAI's Zero Data Retention and
+//! has no abuse-monitoring retention by default, so an enterprise key with ZDR
+//! can serve dictation without audio or transcripts being stored by the
+//! provider. This adapter never logs either.
+
+use crate::domain::{DictationError, Recording, Transcript, TranscriptionProvider};
+use async_openai::{
+ Client,
+ config::OpenAIConfig,
+ error::OpenAIError,
+ types::audio::{AudioInput, AudioResponseFormat, CreateTranscriptionRequest},
+};
+use macro_env_var::env_vars;
+use serde::Deserialize;
+use std::time::Duration;
+use tracing::instrument::WithSubscriber;
+
+env_vars! {
+ /// Server-side OpenAI credential, injected as `OPENAI_API_KEY`. Never
+ /// exposed to the browser.
+ pub struct OpenaiApiKey;
+}
+
+const MODEL: &str = "whisper-1";
+/// Overall request deadline, including the SDK's retries.
+const REQUEST_TIMEOUT: Duration = Duration::from_secs(90);
+/// Total budget for retrying provider 429/5xx responses before giving up.
+const RETRY_BUDGET: Duration = Duration::from_secs(10);
+
+/// Speech-to-text through OpenAI Whisper.
+pub struct WhisperTranscriber {
+ client: Client,
+}
+
+/// The subset of the `verbose_json` response this adapter relies on.
+#[derive(Deserialize)]
+struct VerboseTranscription {
+ text: String,
+ duration: f32,
+}
+
+impl WhisperTranscriber {
+ /// Construct once at startup against the public OpenAI API.
+ pub fn new(api_key: &OpenaiApiKey) -> Result {
+ Self::with_api_base(api_key, None)
+ }
+
+ /// Construct against a custom API base, e.g. a test server.
+ pub fn with_api_base(
+ api_key: &OpenaiApiKey,
+ api_base: Option<&str>,
+ ) -> Result {
+ if api_key.trim().is_empty() {
+ return Err(WhisperConfigError::EmptyApiKey);
+ }
+ let config = OpenAIConfig::new()
+ .with_api_key(api_key.as_ref())
+ .with_api_base(api_base.unwrap_or("https://api.openai.com/v1"));
+ let http_client = reqwest::Client::builder()
+ .timeout(REQUEST_TIMEOUT)
+ .build()?;
+ let backoff = backoff::ExponentialBackoffBuilder::new()
+ .with_max_elapsed_time(Some(RETRY_BUDGET))
+ .build();
+ Ok(Self {
+ client: Client::build(http_client, config, backoff),
+ })
+ }
+}
+
+/// Startup failures for [`WhisperTranscriber::new`].
+#[derive(Debug, thiserror::Error)]
+pub enum WhisperConfigError {
+ /// The required credential contains no usable key.
+ #[error("OPENAI_API_KEY must not be empty")]
+ EmptyApiKey,
+ /// The HTTP client could not be constructed.
+ #[error(transparent)]
+ HttpClient(#[from] reqwest::Error),
+}
+
+impl TranscriptionProvider for WhisperTranscriber {
+ fn model_id(&self) -> &'static str {
+ MODEL
+ }
+
+ #[tracing::instrument(name = "transcribe whisper-1", skip_all, err, fields(
+ otel.kind = "client",
+ gen_ai.operation.name = "transcribe",
+ gen_ai.provider.name = "openai",
+ gen_ai.request.model = MODEL,
+ audio.format = recording.format().extension(),
+ audio.bytes = recording.bytes().len(),
+ audio.duration_seconds = tracing::field::Empty,
+ error.type = tracing::field::Empty,
+ ))]
+ async fn transcribe(&self, recording: Recording) -> Result {
+ let (bytes, format, language) = recording.into_parts();
+ let request = CreateTranscriptionRequest {
+ file: AudioInput::from_bytes(format.filename(), bytes),
+ model: MODEL.to_owned(),
+ language: language.map(|hint| hint.to_string()),
+ response_format: Some(AudioResponseFormat::VerboseJson),
+ ..Default::default()
+ };
+ let audio_api = self.client.audio();
+ let transcriptions = audio_api.transcription();
+ let transcription =
+ transcriptions.create_verbose_json_byot::<_, VerboseTranscription>(request);
+ // async-openai 0.36 logs raw response bodies on parse/HTTP failures.
+ // Scope a silent subscriber to this future's polls only; our surrounding
+ // span and sanitized diagnostics remain visible, including after await.
+ let response = tokio::time::timeout(
+ REQUEST_TIMEOUT,
+ transcription.with_subscriber(tracing::Dispatch::none()),
+ )
+ .await
+ .map_err(|_| {
+ tracing::Span::current().record("error.type", "timeout");
+ tracing::warn!(kind = "timeout", "Whisper request failed");
+ DictationError::Provider
+ })?
+ .map_err(|error| {
+ let kind = match &error {
+ OpenAIError::Reqwest(error) if error.is_timeout() => "timeout",
+ OpenAIError::Reqwest(error) if error.is_connect() => "connection",
+ OpenAIError::Reqwest(_) => "http",
+ OpenAIError::ApiError(_) => "provider_rejection",
+ OpenAIError::JSONDeserialize(..) => "invalid_response",
+ _ => "client_error",
+ };
+ tracing::Span::current().record("error.type", kind);
+ // ApiError discards HTTP headers/status. Only Reqwest retains status;
+ // never recover it by logging the SDK error or its raw body.
+ let status = match &error {
+ OpenAIError::Reqwest(error) => error.status().map(|status| status.as_u16()),
+ _ => None,
+ };
+ tracing::warn!(kind, status, "Whisper request failed");
+ DictationError::Provider
+ })?;
+ if !response.duration.is_finite() || response.duration <= 0.0 {
+ tracing::Span::current().record("error.type", "invalid_duration");
+ tracing::warn!(kind = "invalid_duration", "Whisper response unusable");
+ return Err(DictationError::Provider);
+ }
+ tracing::Span::current().record("audio.duration_seconds", response.duration);
+ Ok(Transcript {
+ text: response.text,
+ duration_seconds: response.duration,
+ })
+ }
+}
+
+#[cfg(test)]
+mod test;
diff --git a/crates/dictation/src/outbound/whisper/test.rs b/crates/dictation/src/outbound/whisper/test.rs
new file mode 100644
index 00000000000..07ed331876b
--- /dev/null
+++ b/crates/dictation/src/outbound/whisper/test.rs
@@ -0,0 +1,105 @@
+use super::*;
+use crate::domain::AudioFormat;
+use bytes::Bytes;
+use serde_json::json;
+use wiremock::matchers::{header, method, path};
+use wiremock::{Mock, MockServer, Request, ResponseTemplate};
+
+/// Minimal Ogg page header so container detection yields `.ogg`.
+const OGG_HEADER: &[u8] = b"OggS\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00";
+
+fn transcriber(server: &MockServer) -> WhisperTranscriber {
+ let api_key = OpenaiApiKey::new_testing("test-server-key");
+ WhisperTranscriber::with_api_base(&api_key, Some(&format!("{}/v1", server.uri()))).unwrap()
+}
+
+fn recording() -> Recording {
+ Recording::new(Bytes::from_static(OGG_HEADER), Some("en".parse().unwrap())).unwrap()
+}
+
+fn multipart_body(request: &Request) -> String {
+ String::from_utf8_lossy(&request.body).into_owned()
+}
+
+#[tokio::test]
+async fn posts_whisper_multipart_with_server_credential_and_reads_duration() {
+ let server = MockServer::start().await;
+ Mock::given(method("POST"))
+ .and(path("/v1/audio/transcriptions"))
+ .and(header("authorization", "Bearer test-server-key"))
+ .respond_with(ResponseTemplate::new(200).set_body_json(json!({
+ "task": "transcribe",
+ "language": "english",
+ "duration": 2.5,
+ "text": "Hello.",
+ "segments": []
+ })))
+ .expect(1)
+ .mount(&server)
+ .await;
+
+ let transcript = transcriber(&server).transcribe(recording()).await.unwrap();
+
+ assert_eq!(transcript.text, "Hello.");
+ assert_eq!(transcript.duration_seconds, 2.5);
+ let requests = server.received_requests().await.unwrap();
+ let body = multipart_body(&requests[0]);
+ for expected in [
+ "name=\"model\"\r\n\r\nwhisper-1",
+ "name=\"response_format\"\r\n\r\nverbose_json",
+ "name=\"language\"\r\n\r\nen",
+ "filename=\"dictation.ogg\"",
+ "OggS",
+ ] {
+ assert!(body.contains(expected), "missing {expected:?} in {body:?}");
+ }
+ assert_eq!(recording().format(), AudioFormat::Ogg);
+}
+
+#[tokio::test]
+async fn rejects_responses_without_billable_duration() {
+ let server = MockServer::start().await;
+ Mock::given(method("POST"))
+ .and(path("/v1/audio/transcriptions"))
+ .respond_with(ResponseTemplate::new(200).set_body_json(json!({ "text": "Only text." })))
+ .mount(&server)
+ .await;
+
+ assert_eq!(
+ transcriber(&server).transcribe(recording()).await,
+ Err(DictationError::Provider)
+ );
+}
+
+#[test]
+fn rejects_empty_credentials_at_construction() {
+ assert!(matches!(
+ WhisperTranscriber::new(&OpenaiApiKey::new_testing(" ")),
+ Err(WhisperConfigError::EmptyApiKey)
+ ));
+}
+
+#[tokio::test]
+async fn maps_provider_rejections_to_a_content_free_error() {
+ let server = MockServer::start().await;
+ Mock::given(method("POST"))
+ .and(path("/v1/audio/transcriptions"))
+ .respond_with(ResponseTemplate::new(400).set_body_json(json!({
+ "error": {
+ "message": "Invalid file format.",
+ "type": "invalid_request_error",
+ "param": "file",
+ "code": null
+ }
+ })))
+ .expect(1)
+ .mount(&server)
+ .await;
+
+ let error = transcriber(&server)
+ .transcribe(recording())
+ .await
+ .unwrap_err();
+
+ assert_eq!(error, DictationError::Provider);
+}
diff --git a/crates/dictation/tests/fixtures/README.md b/crates/dictation/tests/fixtures/README.md
new file mode 100644
index 00000000000..a761bc87a3f
--- /dev/null
+++ b/crates/dictation/tests/fixtures/README.md
@@ -0,0 +1,35 @@
+# Dictation media fixtures
+
+These fixtures contain generated tones or silence, with no recorded speech.
+They exercise container parsing, including Opus and fragmented MP4, without
+requiring a codec decoder, FFmpeg, a microphone, or elapsed-time waits in tests.
+
+Generate each `tone` file with FFmpeg using this input:
+
+```sh
+ffmpeg -f lavfi -i 'sine=frequency=440:sample_rate=16000:duration=0.1' ...
+```
+
+Output options:
+
+| File | Options |
+| --- | --- |
+| `tone.webm` | `-c:a libopus tone.webm` |
+| `tone.ogg` | `-c:a libopus tone.ogg` |
+| `tone.mp4` | `-c:a aac -movflags frag_keyframe+empty_moov+default_base_moof tone.mp4` |
+| `tone.wav` | `-c:a pcm_s16le tone.wav` |
+
+The duration-limit fixture is generated with:
+
+```sh
+ffmpeg -f lavfi -i 'anullsrc=r=16000:cl=mono' -t 301 -c:a libopus long.ogg
+```
+
+`chrome.webm` was captured in Chromium 152 using the production `AudioRecorder`,
+with a Web Audio oscillator connected to a `MediaStreamAudioDestinationNode`
+instead of a microphone. It uses WebM/Opus at 64 kbit/s and stops after the first
+`dataavailable` event. Unlike the FFmpeg fixture, its container has no declared
+duration or packet durations; the inspector must read packet timestamps and
+Opus framing. FFprobe reports four 60 ms packets, with the last starting at
+180 ms, for a total of 240 ms.
+
diff --git a/crates/dictation/tests/fixtures/chrome.webm b/crates/dictation/tests/fixtures/chrome.webm
new file mode 100644
index 00000000000..7da5a9a3a1f
Binary files /dev/null and b/crates/dictation/tests/fixtures/chrome.webm differ
diff --git a/crates/dictation/tests/fixtures/long.ogg b/crates/dictation/tests/fixtures/long.ogg
new file mode 100644
index 00000000000..a1b56426cff
Binary files /dev/null and b/crates/dictation/tests/fixtures/long.ogg differ
diff --git a/crates/dictation/tests/fixtures/tone.mp4 b/crates/dictation/tests/fixtures/tone.mp4
new file mode 100644
index 00000000000..12428000080
Binary files /dev/null and b/crates/dictation/tests/fixtures/tone.mp4 differ
diff --git a/crates/dictation/tests/fixtures/tone.ogg b/crates/dictation/tests/fixtures/tone.ogg
new file mode 100644
index 00000000000..9a25da72046
Binary files /dev/null and b/crates/dictation/tests/fixtures/tone.ogg differ
diff --git a/crates/dictation/tests/fixtures/tone.wav b/crates/dictation/tests/fixtures/tone.wav
new file mode 100644
index 00000000000..098d8365e2b
Binary files /dev/null and b/crates/dictation/tests/fixtures/tone.wav differ
diff --git a/crates/dictation/tests/fixtures/tone.webm b/crates/dictation/tests/fixtures/tone.webm
new file mode 100644
index 00000000000..6c09c25da34
Binary files /dev/null and b/crates/dictation/tests/fixtures/tone.webm differ
diff --git a/crates/dictation/tests/whisper_tracing.rs b/crates/dictation/tests/whisper_tracing.rs
new file mode 100644
index 00000000000..9ec1056b288
--- /dev/null
+++ b/crates/dictation/tests/whisper_tracing.rs
@@ -0,0 +1,78 @@
+//! Exercise SDK logging with an isolated subscriber; unrelated parallel tests
+//! must not alter callsite registration while the capture is active.
+#![cfg(feature = "outbound")]
+
+use bytes::Bytes;
+use dictation::{
+ domain::{DictationError, Recording, TranscriptionProvider},
+ outbound::{OpenaiApiKey, WhisperTranscriber},
+};
+use serde_json::json;
+use tracing::instrument::WithSubscriber;
+use wiremock::{Mock, MockServer, ResponseTemplate, matchers::method};
+
+#[derive(Clone, Default)]
+struct CapturedLogs(std::sync::Arc>>);
+
+impl std::io::Write for CapturedLogs {
+ fn write(&mut self, bytes: &[u8]) -> std::io::Result {
+ self.0.lock().unwrap().extend_from_slice(bytes);
+ Ok(bytes.len())
+ }
+
+ fn flush(&mut self) -> std::io::Result<()> {
+ Ok(())
+ }
+}
+
+impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for CapturedLogs {
+ type Writer = Self;
+ fn make_writer(&'a self) -> Self {
+ self.clone()
+ }
+}
+
+#[tokio::test]
+async fn malformed_provider_responses_never_log_transcript_content() {
+ for status in [200, 400] {
+ let server = MockServer::start().await;
+ Mock::given(method("POST"))
+ .respond_with(ResponseTemplate::new(status).set_body_json(
+ json!({"text": "PRIVATE_TRANSCRIPT_SENTINEL", "duration": "invalid"}),
+ ))
+ .expect(1)
+ .mount(&server)
+ .await;
+ let logs = CapturedLogs::default();
+ let subscriber = tracing_subscriber::fmt()
+ .without_time()
+ .with_ansi(false)
+ .with_span_events(tracing_subscriber::fmt::format::FmtSpan::CLOSE)
+ .with_max_level(tracing::Level::TRACE)
+ .with_writer(logs.clone())
+ .finish();
+ let transcriber = WhisperTranscriber::with_api_base(
+ &OpenaiApiKey::Comptime("test-server-key"),
+ Some(&format!("{}/v1", server.uri())),
+ )
+ .unwrap();
+ let recording = Recording::new(
+ Bytes::from_static(include_bytes!("fixtures/tone.ogg")),
+ None,
+ )
+ .unwrap();
+ let result = transcriber
+ .transcribe(recording)
+ .with_subscriber(subscriber)
+ .await;
+ assert_eq!(result, Err(DictationError::Provider));
+ let output = String::from_utf8(logs.0.lock().unwrap().clone()).unwrap();
+ assert!(
+ output.contains("Whisper request failed") && output.contains("invalid_response"),
+ "sanitized diagnostics must remain visible: {output}"
+ );
+ assert!(!output.contains("PRIVATE_TRANSCRIPT_SENTINEL"));
+ assert!(!output.contains("test-server-key"));
+ assert!(output.contains("gen_ai.request.model=\"whisper-1\""));
+ }
+}
diff --git a/crates/macro_db_client/migrations/20260918204004_add_audio_usage_pricing.sql b/crates/macro_db_client/migrations/20260918204004_add_audio_usage_pricing.sql
new file mode 100644
index 00000000000..75388cb11f4
--- /dev/null
+++ b/crates/macro_db_client/migrations/20260918204004_add_audio_usage_pricing.sql
@@ -0,0 +1,17 @@
+-- Add duration billing alongside token billing; deployed token-only writers can
+-- continue omitting every new column.
+ALTER TABLE ai_pricing
+ ADD COLUMN price_per_audio_minute REAL
+ CHECK (price_per_audio_minute >= 0 AND price_per_audio_minute < 'Infinity'::real);
+
+ALTER TABLE ai_usage
+ ADD COLUMN audio_seconds DOUBLE PRECISION
+ CHECK (audio_seconds >= 0 AND audio_seconds < 'Infinity'::double precision),
+ ADD COLUMN price_per_audio_minute REAL
+ CHECK (price_per_audio_minute >= 0 AND price_per_audio_minute < 'Infinity'::real);
+
+-- https://platform.openai.com/docs/pricing — Whisper is priced per audio minute.
+-- Preserve any rate already configured by an administrator.
+INSERT INTO ai_pricing (model, price_per_million_in, price_per_million_out, price_per_audio_minute)
+VALUES ('whisper-1', 0, 0, 0.006)
+ON CONFLICT (model) DO NOTHING;
diff --git a/crates/macro_db_migrator/src/bin/comment_import/test.rs b/crates/macro_db_migrator/src/bin/comment_import/test.rs
index a20de15d6a0..b5651467851 100644
--- a/crates/macro_db_migrator/src/bin/comment_import/test.rs
+++ b/crates/macro_db_migrator/src/bin/comment_import/test.rs
@@ -567,7 +567,7 @@ async fn other_connection(pool: &PgPool) -> PgConnection {
async fn release_import_lock(connection: &mut PgConnection) {
// Closing the client does not wait for PostgreSQL to release session locks.
- // Await an explicit unlock before another connection tries to run the import.
+ // Await an explicit unlock before another connection tries to acquire it.
assert!(
sqlx::query_scalar!(r#"SELECT pg_advisory_unlock($1) AS "released!""#, LOCK_ID)
.fetch_one(connection)
diff --git a/crates/workspace-hack/Cargo.toml b/crates/workspace-hack/Cargo.toml
index 61dc98cc239..3489129c938 100644
--- a/crates/workspace-hack/Cargo.toml
+++ b/crates/workspace-hack/Cargo.toml
@@ -19,6 +19,7 @@ aes-gcm = { version = "0.10", features = ["zeroize"] }
ahash = { version = "0.8" }
aho-corasick = { version = "1" }
anyhow = { version = "1" }
+async-openai = { version = "0.36", features = ["audio", "byot", "chat-completion", "completions", "embedding"] }
aws-config = { version = "1", features = ["behavior-version-latest"] }
aws-credential-types = { version = "1", default-features = false, features = ["hardcoded-credentials", "test-util"] }
aws-runtime = { version = "1", default-features = false, features = ["event-stream", "http-02x", "http-1x", "sigv4a"] }
@@ -34,6 +35,7 @@ axum = { version = "0.8", features = ["macros", "multipart", "ws"] }
axum-extra = { version = "0.10", features = ["cookie", "query", "typed-header"] }
base64 = { version = "0.22" }
bstr = { version = "1" }
+bytemuck = { version = "1", default-features = false, features = ["extern_crate_alloc"] }
byteorder = { version = "1" }
bytes = { version = "1", features = ["serde"] }
bzip2 = { version = "0.5", features = ["libbz2-rs-sys"] }
@@ -152,6 +154,7 @@ aes-gcm = { version = "0.10", features = ["zeroize"] }
ahash = { version = "0.8" }
aho-corasick = { version = "1" }
anyhow = { version = "1" }
+async-openai = { version = "0.36", features = ["audio", "byot", "chat-completion", "completions", "embedding"] }
aws-config = { version = "1", features = ["behavior-version-latest"] }
aws-credential-types = { version = "1", default-features = false, features = ["hardcoded-credentials", "test-util"] }
aws-runtime = { version = "1", default-features = false, features = ["event-stream", "http-02x", "http-1x", "sigv4a"] }
@@ -167,6 +170,7 @@ axum = { version = "0.8", features = ["macros", "multipart", "ws"] }
axum-extra = { version = "0.10", features = ["cookie", "query", "typed-header"] }
base64 = { version = "0.22" }
bstr = { version = "1" }
+bytemuck = { version = "1", default-features = false, features = ["extern_crate_alloc"] }
byteorder = { version = "1" }
bytes = { version = "1", features = ["serde"] }
bzip2 = { version = "0.5", features = ["libbz2-rs-sys"] }
diff --git a/deny.toml b/deny.toml
index 30a7c69b06c..ccf12256039 100644
--- a/deny.toml
+++ b/deny.toml
@@ -207,6 +207,7 @@ deny = [
"channels", # Dev logging only
"coding_agent_worker", # Standalone daemon logging setup
"cursor_cloud_agents", # Standalone ACP binary logging; stdout is the protocol, so macro_entrypoint cannot own it
+ "dictation", # Metadata tracing and content-redaction tests only
"documents", # Dev logging only
"email", # Dev logging only
"genai_telemetry", # GenAI span tests
diff --git a/docs/AGENT_GUIDE/ai-chat.md b/docs/AGENT_GUIDE/ai-chat.md
index 14c5e999fe1..050820140af 100644
--- a/docs/AGENT_GUIDE/ai-chat.md
+++ b/docs/AGENT_GUIDE/ai-chat.md
@@ -263,6 +263,45 @@ notified when the AI responds). Legacy Home background sends preserve the submit
## Composer anatomy (a11y)
+AI chat (including Home and doc-scoped chat) and agent session composers have
+a **Start dictation with OpenAI Whisper** microphone beside Send. It records
+in memory and uploads to the
+authenticated `/dictation/transcribe` storage endpoint only on confirmation.
+Whisper is available on all plans without consuming chat credits; its server
+credential is never exposed to the browser. Unsupported recording environments
+show a disabled microphone. Every supported browser uses Whisper; there are
+no browser speech-recognition or language-pack installation flows.
+
+While dictating, a scrolling microphone-volume timeline and **Cancel dictation** / **Use dictation**
+replace the composer controls. Cancel (or Escape) preserves the original draft.
+Bars sample microphone volume as recording chunks arrive (normally every 200ms): silence stays dotted, louder speech
+creates taller bars, and earlier levels move left without changing height.
+Volume analysis stays on-device and stops on confirm, cancel, error, or close.
+Use dictation stops recording, waits for Whisper, and appends plain text to
+the draft without sending it. Existing rich text and attachments remain intact.
+If the browser stops listening on its own, **Ready** waits for confirmation.
+While **Finishing…**, the checkmark is disabled and Cancel remains available.
+Mobile chat stays expanded when focus moves into dictation controls.
+Starting dictation in another composer releases the previous session without
+moving focus back to it. Closing the composer releases the microphone. Capture failures
+appear below the composer.
+
+Whisper dictation supports WebM, MP4, and Ogg recording depending on browser.
+Recordings stop just before five minutes or near 8 MB and wait for confirmation.
+Cancel discards the recording; cancel during transcription aborts the request and
+ignores any late result. If the service is temporarily at capacity, the composer
+stays in **Finishing…** while TanStack retries up to twice with exponential backoff,
+jitter, and the server's `Retry-After` delay. Cancel also cancels these retries.
+Other failures keep the recording in memory for an explicit retry with the
+checkmark. No audio or transcript is stored in the query cache or persisted by the dictation
+endpoint. Provider diagnostics exclude response content. The server detects
+the audio container and inspects its duration before contacting OpenAI, requires a
+signed-in user (bots and internal callers are refused), and rate limits each
+user to 60 attempts per hour (failed requests and retries count). Hourly limits
+show “Dictation limit reached. Please try again later.” and are not automatically retried.
+The backend records provider-reported audio seconds in the shared AI usage system
+and uses Whisper's per-minute model pricing without charging user credits.
+
Desktop composer and conversation body text use 15px type. Mobile keeps its
existing text sizing.
diff --git a/docs/AGENT_GUIDE/channels.md b/docs/AGENT_GUIDE/channels.md
index 4874574e8fe..78e923c2b8a 100644
--- a/docs/AGENT_GUIDE/channels.md
+++ b/docs/AGENT_GUIDE/channels.md
@@ -38,6 +38,16 @@ show whatever has arrived so far.
## Message composer
+Channel messages and thread replies have a microphone next to Send, including
+the collapsed composer. It uses the same OpenAI Whisper dictation and scrolling
+volume timeline as AI chat. **Use dictation** appends text to the draft without
+sending; **Cancel dictation** or Escape preserves the existing draft. Sending
+is blocked during dictation, including keyboard and external send actions.
+When local recognition is unavailable, confirming uploads the in-memory audio
+to Whisper. This fallback is available on all plans without consuming chat credits.
+Browsers without microphone recording show a disabled button.
+The first click downloads a language pack when needed; click again to record.
+
Composer and conversation body text use `text-base` (15px at the default root
size) on desktop and mobile. The shared scale uses 14px for `text-sm` and 12px
for `text-xs`, with accessibility text scaling preserved.
diff --git a/nix-support/node_modules-hashes.json b/nix-support/node_modules-hashes.json
index c0b39f08763..973d8e68ed3 100644
--- a/nix-support/node_modules-hashes.json
+++ b/nix-support/node_modules-hashes.json
@@ -1,6 +1,6 @@
{
"nodeModules": {
- "aarch64-darwin": "sha256-UdoatrQ33Socze4bAzdZS/NvIC1Uc1Z+A7n9QXEFunA=",
- "x86_64-linux": "sha256-aQvn+NvaP9aUvoZyz4fPhS9/3xcyP4/XPlV9etbUMOM="
+ "x86_64-linux": "sha256-euQs05yQlRl3TE2TunEjX1dvQIAIAL+v16meI7VNa5A=",
+ "aarch64-darwin": "sha256-FO99wNeI8e3GYKkNShok27bFcEQxUddMB8VKaCmGck8="
}
}
diff --git a/packages/sdk/generated/cognition/types.gen.ts b/packages/sdk/generated/cognition/types.gen.ts
index e038e212567..66d77e7b9c9 100644
--- a/packages/sdk/generated/cognition/types.gen.ts
+++ b/packages/sdk/generated/cognition/types.gen.ts
@@ -27,7 +27,7 @@ export type AddServerRequest = {
* Everything we use AI for. The wire / DB form of each variant is its
* `snake_case` name.
*/
-export type AiFeature = 'chat' | 'memory' | 'automation' | 'dynamic_completions_api' | 'chat_rename' | 'call_summary' | 'channel_bot' | 'ai_projection' | 'ai_editing' | 'import' | 'agent_session' | 'agent_repository_choice';
+export type AiFeature = 'chat' | 'memory' | 'automation' | 'dynamic_completions_api' | 'chat_rename' | 'call_summary' | 'channel_bot' | 'ai_projection' | 'ai_editing' | 'import' | 'agent_session' | 'agent_repository_choice' | 'dictation';
/**
* A structured part within an assistant message.
@@ -400,24 +400,23 @@ export type CompleteOnboardingRequest = {
};
/**
- * A recorded completion: who, what feature, optional entity, and the cost.
+ * User and feature attribution for one invocation.
*/
export type CompletionUsage = {
/**
- * Token usage and cost.
+ * Measured usage and resolved cost.
*/
cost: Usage;
/**
- * The entity the completion related to, if any.
+ * Related entity, if any.
*/
entity?: string | null;
/**
- * The feature that performed the completion.
+ * Feature that performed the invocation.
*/
feature: AiFeature;
/**
- * The user the completion was performed for (the [system user](SYSTEM_USER_ID)
- * for background work).
+ * User the invocation was performed for.
*/
user: MacroUserIdStr;
};
@@ -537,19 +536,19 @@ export type ErrorResponse = {
export type Expiry = 'day' | 'week' | 'month';
/**
- * Usage for a single feature, with its rolled-up dollar total.
+ * Recorded invocations and total for one feature.
*/
export type FeatureUsage = {
/**
- * The individual completions recorded for this feature.
+ * Recorded invocations.
*/
entries: Array;
/**
- * The feature.
+ * Feature attribution.
*/
feature: AiFeature;
/**
- * Total cost across `entries` (USD).
+ * Total cost (USD).
*/
total: number;
};
@@ -1073,19 +1072,23 @@ export type PipedreamUpdateRequest = {
};
/**
- * Resolved price for one completion.
+ * Rates applied to an invocation and its resolved dollar cost.
*/
export type Price = {
/**
- * Price per million input tokens (USD).
+ * Price per audio minute (USD), absent for token billing.
+ */
+ price_per_audio_minute?: number | null;
+ /**
+ * Price per million input tokens (USD); zero for audio billing.
*/
price_per_million_in: number;
/**
- * Price per million output tokens (USD).
+ * Price per million output tokens (USD); zero for audio billing.
*/
price_per_million_out: number;
/**
- * Total cost of the completion (USD).
+ * Total cost (USD).
*/
total: number;
};
@@ -1263,13 +1266,17 @@ export type SetPricingRequest = {
*/
model: string;
/**
- * New price per million input tokens (USD).
+ * Price per minute of audio (USD), or null for token-only pricing.
*/
- price_per_mil_in: number;
+ price_per_audio_minute?: number | null;
/**
- * New price per million output tokens (USD).
+ * New price per million input tokens (USD). Required for token pricing.
*/
- price_per_mil_out: number;
+ price_per_mil_in?: number | null;
+ /**
+ * New price per million output tokens (USD). Required for token pricing.
+ */
+ price_per_mil_out?: number | null;
};
export type SharePermissionV2 = {
@@ -1560,23 +1567,27 @@ export type UpsertProjectionRequest = {
};
/**
- * The token usage and resolved cost of a single completion.
+ * Measured usage for one invocation.
*/
export type Usage = {
/**
- * When the completion was recorded.
+ * Audio duration in seconds, absent for token billing.
+ */
+ audio_seconds?: number | null;
+ /**
+ * Recording timestamp.
*/
created_at: string;
/**
- * Tokens consumed by the input.
+ * Input tokens; zero for audio billing.
*/
input_tokens: number;
/**
- * The model api id (e.g. `claude-opus-4-8`).
+ * Provider model identifier.
*/
model: string;
/**
- * Tokens generated in the output.
+ * Output tokens; zero for audio billing.
*/
output_tokens: number;
price?: null | Price;
@@ -1605,7 +1616,7 @@ export type UsageRequest = {
};
/**
- * The result of a usage query: per-feature breakdown plus a grand total.
+ * Per-feature breakdown and grand total.
*/
export type UsageSummary = {
/**
@@ -1613,7 +1624,7 @@ export type UsageSummary = {
*/
entries: Array;
/**
- * Grand total cost across all features (USD).
+ * Grand total (USD).
*/
total: number;
};
@@ -1677,6 +1688,10 @@ export type SetPricingHandlerData = {
};
export type SetPricingHandlerErrors = {
+ /**
+ * Invalid pricing
+ */
+ 400: ErrorBody;
/**
* Admin access required
*/
diff --git a/packages/sdk/generated/storage/index.ts b/packages/sdk/generated/storage/index.ts
index 043fd879794..65d9febdd33 100644
--- a/packages/sdk/generated/storage/index.ts
+++ b/packages/sdk/generated/storage/index.ts
@@ -1,4 +1,4 @@
// This file is auto-generated by @hey-api/openapi-ts
export { type Options, Sdk } from './sdk.gen';
-export type { AccessLevel, ActiveCallsResponse, ActiveCallSummary, ActivityType, AddFavoriteData, AddFavoriteError, AddFavoriteErrors, AddFavoriteRequest, AddFavoriteResponse, AddFavoriteResponses, AddParticipantsData, AddParticipantsError, AddParticipantsErrors, AddParticipantsRequest, AddParticipantsResponses, AddPinHandlerData, AddPinHandlerError, AddPinHandlerErrors, AddPinHandlerResponse, AddPinHandlerResponses, AddPinRequest, Agent, AgentActionId, AgentChannelScope, AgentMcpServer, AgentMcpServers, AgentSessionFilters, AgentSessionLifecycleEvent, Anchor, AnchorId, AnchorRequest, AnchorResponse, AnnotationIncrementalUpdate, ApiActivity, ApiAttachmentChannelReference, ApiAttachmentEntityReference, ApiAttachmentGenericReference, ApiChannelAttachment, ApiChannelAttachmentsPage, ApiChannelContextMessage, ApiChannelDetail, ApiChannelListMessage, ApiChannelListPage, ApiChannelListParticipant, ApiChannelListType, ApiChannelMessage, ApiChannelMessageKind, ApiChannelMessagesPage, ApiChannelParticipant, ApiChannelWithLatest, ApiCountedReaction, ApiEntityFilterAst, ApiGroupByField, ApiGroupMeta, ApiMessageAttachment, ApiMessageSender, ApiMessageSenderType, ApiParticipantListRole, ApiParticipantRole, ApiPropertyEntityType, ApiResolvedChannelMessage, ApiThreadInfo, ApiThreadReply, ApproveHarnessPairingData, ApproveHarnessPairingError, ApproveHarnessPairingErrors, ApproveHarnessPairingResponse, ApproveHarnessPairingResponses, ApprovePairingRequest, AssignInitiativeTasksData, AssignInitiativeTasksError, AssignInitiativeTasksErrors, AssignInitiativeTasksResponse, AssignInitiativeTasksResponses, AssignTasksRequest, AssignTasksResponse, AssignTasksResult, AssignTaskStatus, AttachmentChange, AttendeeResponseStatus, BasicDocument, BasicDocumentSubType, BomPart, Bot, BotChannel, BotChannelType, BotId, BotKind, BotOwner, BotSenderProfile, BotToken, BranchNameResponse, BTreeMap, BulkWakeupRequest, BulkWakeupResponse, BulkWakeupSyncServiceDocumentsData, BulkWakeupSyncServiceDocumentsErrors, BulkWakeupSyncServiceDocumentsResponse, BulkWakeupSyncServiceDocumentsResponses, CalendarAttendee, CalendarEvent, CalendarEventFilters, CalendarEventSourceContent, CalendarMentionEvent, CalendarMentionPreviewItem, CalendarMentionPreviewKind, CalendarMentionPreviewRequest, CalendarMentionPreviewRequestItem, CalendarMentionPreviewResponse, CalendarOccurrence, CalendarOccurrenceItem, CalendarOccurrenceResponse, CalendarSyncStatus, CallActiveResponse, CallFilters, CallRecord, CallRecordParticipant, CallRecordPreview, CallRecordPreviewData, CallRecordTranscriptSegment, CallStatus, CallTokenResponse, CallWebhookData, CallWebhookError, CallWebhookErrors, CallWebhookResponses, Channel, ChannelCreatedMetadata, ChannelDeletedMetadata, ChannelEventAttachment, ChannelFilters, ChannelJoinCodeResponse, ChannelMentionedMetadata, ChannelMessage, ChannelMessageAttachmentCreatedMetadata, ChannelMessageAttachmentRemovedMetadata, ChannelMessageDeletedMetadata, ChannelMessageFilters, ChannelMessagePatchedMetadata, ChannelMessagePostedMetadata, ChannelParticipant, ChannelParticipantAddedMetadata, ChannelParticipantRemovedMetadata, ChannelPreview, ChannelPreviewData, ChannelSender, ChannelSharePermission, ChannelThreadFilters, ChannelTopicEvent, ChannelType, ChannelUpdatedMetadata, ChannelWebhookRequest, ChannelWebhookResponse, ChannelWithParticipants, Chat, ChatFilters, CheckActiveCallData, CheckActiveCallError, CheckActiveCallErrors, CheckActiveCallResponse, CheckActiveCallResponses, ClaimedPairing, ClaimHarnessPairingData, ClaimHarnessPairingError, ClaimHarnessPairingErrors, ClaimHarnessPairingResponse, ClaimHarnessPairingResponses, ClaimPairingRequest, ClientOptions, CloudStorageItemType, CollabSurfaceResponse, CollabSurfaceTokenResponse, Comment, CommentThread, ConferenceProvider, CopyDocumentData, CopyDocumentError, CopyDocumentErrors, CopyDocumentQueryParams, CopyDocumentRequest, CopyDocumentResponse, CopyDocumentResponse2, CopyDocumentResponses, CountedReaction, CreateAgentData, CreateAgentError, CreateAgentErrors, CreateAgentRequest, CreateAgentResponse, CreateAgentResponses, CreateAnchorData, CreateAnchorError, CreateAnchorErrors, CreateAnchorResponse, CreateAnchorResponses, CreateBotRequest, CreateBulkDocumentResponse, CreateBulkDocumentResponseData, CreateChannelData, CreateChannelError, CreateChannelErrors, CreateChannelRequest, CreateChannelResponse, CreateChannelResponse2, CreateChannelResponses, CreateChannelScopedBotData, CreateChannelScopedBotError, CreateChannelScopedBotErrors, CreateChannelScopedBotRequest, CreateChannelScopedBotResponse, CreateChannelScopedBotResponse2, CreateChannelScopedBotResponses, CreateCollabSurfaceTokenData, CreateCollabSurfaceTokenError, CreateCollabSurfaceTokenErrors, CreateCollabSurfaceTokenResponse, CreateCollabSurfaceTokenResponses, CreateCommentData, CreateCommentError, CreateCommentErrors, CreateCommentRequest, CreateCommentResponse, CreateCommentResponse2, CreateCommentResponses, CreateCrmCommentData, CreateCrmCommentError, CreateCrmCommentErrors, CreateCrmCommentRequest, CreateCrmCommentResponse, CreateCrmCommentResponses, CreateCrmCompanyData, CreateCrmCompanyError, CreateCrmCompanyErrors, CreateCrmCompanyRequest, CreateCrmCompanyResponse, CreateCrmCompanyResponses, CreateCrmContactData, CreateCrmContactError, CreateCrmContactErrors, CreateCrmContactRequest, CreateCrmContactResponse, CreateCrmContactResponses, CreateDocumentData, CreateDocumentError, CreateDocumentErrors, CreateDocumentRequest, CreateDocumentResponse, CreateDocumentResponseData, CreateDocumentResponses, CreatedPairing, CreatedUserApiKey, CreateEntityMentionData, CreateEntityMentionError, CreateEntityMentionErrors, CreateEntityMentionRequest, CreateEntityMentionResponse, CreateEntityMentionResponse2, CreateEntityMentionResponses, CreateHarnessPairingData, CreateHarnessPairingError, CreateHarnessPairingErrors, CreateHarnessPairingResponse, CreateHarnessPairingResponses, CreateInitiativeData, CreateInitiativeError, CreateInitiativeErrors, CreateInitiativeRequest, CreateInitiativeResponse, CreateInitiativeResponses, CreateInstructionsDocumentResponse, CreateInstructionsHandlerData, CreateInstructionsHandlerError, CreateInstructionsHandlerErrors, CreateInstructionsHandlerResponse, CreateInstructionsHandlerResponses, CreateMarkdownDocumentRequest, CreateMarkdownDocumentResponse, CreateMarkdownHandlerData, CreateMarkdownHandlerError, CreateMarkdownHandlerErrors, CreateMarkdownHandlerResponse, CreateMarkdownHandlerResponses, CreatePairingRequest, CreateProjectHandlerData, CreateProjectHandlerError, CreateProjectHandlerErrors, CreateProjectHandlerResponse, CreateProjectHandlerResponses, CreateProjectRequest, CreateProjectResponse, CreateReminderData, CreateReminderError, CreateReminderErrors, CreateReminderRequest, CreateReminderResponse, CreateReminderResponses, CreateSkillHandlerData, CreateSkillHandlerError, CreateSkillHandlerErrors, CreateSkillHandlerResponse, CreateSkillHandlerResponses, CreateSkillRequest, CreateSkillResponse, CreateSnippetHandlerData, CreateSnippetHandlerError, CreateSnippetHandlerErrors, CreateSnippetHandlerResponse, CreateSnippetHandlerResponses, CreateSnippetRequest, CreateSnippetResponse, CreateTaskHandlerData, CreateTaskHandlerError, CreateTaskHandlerErrors, CreateTaskHandlerResponse, CreateTaskHandlerResponses, CreateTaskRequest, CreateTaskResponse, CreateUnthreadedAnchorRequest, CreateUnthreadedAnchorResponse, CreateUnthreadedPdfAnchorRequest, CreateUserApiKeyData, CreateUserApiKeyError, CreateUserApiKeyErrors, CreateUserApiKeyRequest, CreateUserApiKeyResponse, CreateUserApiKeyResponses, CreateViewHandlerData, CreateViewHandlerError, CreateViewHandlerErrors, CreateViewHandlerResponse, CreateViewHandlerResponses, CreateViewRequest, CreateWebhookData, CreateWebhookError, CreateWebhookErrors, CreateWebhookRequest, CreateWebhookResponse, CreateWebhookResponse2, CreateWebhookResponses, CrmComment, CrmCommentEntityType, CrmCommentThread, CrmCompanyFilters, CrmCompanyResponse, CrmContactResponse, CrmDomainResponse, CrmPermissionRole, CrmStageInput, CrmStageResponse, CrmStagesResponse, CrmTeamSettingsResponse, CrmThread, CustomSpeakerAssignment, DataType, DeleteAnchorData, DeleteAnchorError, DeleteAnchorErrors, DeleteAnchorInfo, DeleteAnchorResponse, DeleteAnchorResponses, DeleteCallRecordData, DeleteCallRecordError, DeleteCallRecordErrors, DeleteCallRecordResponse, DeleteCallRecordResponses, DeleteChannelData, DeleteChannelError, DeleteChannelErrors, DeleteChannelResponse, DeleteChannelResponses, DeleteCollabSurfaceData, DeleteCollabSurfaceError, DeleteCollabSurfaceErrors, DeleteCollabSurfaceResponse, DeleteCollabSurfaceResponses, DeleteCommentData, DeleteCommentError, DeleteCommentErrors, DeleteCommentRequest, DeleteCommentResponse, DeleteCommentResponse2, DeleteCommentResponses, DeleteCrmCommentData, DeleteCrmCommentError, DeleteCrmCommentErrors, DeleteCrmCommentResponse, DeleteCrmCommentResponses, DeleteCrmCommentResult, DeleteDocumentData, DeleteDocumentError, DeleteDocumentErrors, DeleteDocumentResponse, DeleteDocumentResponses, DeleteEntityMentionData, DeleteEntityMentionError, DeleteEntityMentionErrors, DeleteEntityMentionResponse, DeleteEntityMentionResponse2, DeleteEntityMentionResponses, DeleteHarnessData, DeleteHarnessError, DeleteHarnessErrors, DeleteHarnessResponse, DeleteHarnessResponses, DeleteHistoryHandlerData, DeleteHistoryHandlerError, DeleteHistoryHandlerErrors, DeleteHistoryHandlerResponse, DeleteHistoryHandlerResponses, DeleteInitiativeData, DeleteInitiativeError, DeleteInitiativeErrors, DeleteInitiativeResponse, DeleteInitiativeResponses, DeleteMessageData, DeleteMessageError, DeleteMessageErrors, DeleteMessageQuery, DeleteMessageResponse, DeleteMessageResponses, DeleteProjectHandlerData, DeleteProjectHandlerError, DeleteProjectHandlerErrors, DeleteProjectHandlerResponse, DeleteProjectHandlerResponses, DeleteReminderData, DeleteReminderError, DeleteReminderErrors, DeleteReminderResponse, DeleteReminderResponses, DeleteSelfHarnessData, DeleteSelfHarnessError, DeleteSelfHarnessErrors, DeleteSelfHarnessResponse, DeleteSelfHarnessResponses, DeleteThreadInfo, DeleteUnthreadedAnchorRequest, DeleteUnthreadedAnchorResponse, DeleteUnthreadedPdfAnchorRequest, DeleteUserApiKeyData, DeleteUserApiKeyError, DeleteUserApiKeyErrors, DeleteUserApiKeyResponse, DeleteUserApiKeyResponses, DeleteUserDocumentViewLocationData, DeleteUserDocumentViewLocationError, DeleteUserDocumentViewLocationErrors, DeleteUserDocumentViewLocationResponse, DeleteUserDocumentViewLocationResponses, DeleteViewHandlerData, DeleteViewHandlerError, DeleteViewHandlerErrors, DeleteViewHandlerResponses, DeleteWebhookData, DeleteWebhookError, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DescriptionDocumentId, DocumentBasic, DocumentContent, DocumentContentLocation, DocumentContentState, DocumentContentUploadedMetadata, DocumentCopiedMetadata, DocumentCreatedMetadata, DocumentDeletedMetadata, DocumentFilters, DocumentId, DocumentInteractionMetadata, DocumentMetadata, DocumentMetadataWithContent, DocumentPermissionsToken, DocumentPermissionsTokenRequest, DocumentPermissionsTokenResponse, DocumentPreview, DocumentPreviewData, DocumentPreviewDataSubType, DocumentPurgedMetadata, DocumentResponse, DocumentResponseMetadata, DocumentResponseMetadataWithContent, DocumentStorageServiceApiVersion, DocumentSubType, DocumentSyncContentUpdatedMetadata, DocumentTeamShareResponse, DocumentTopicEvent, DocumentUpdatedMetadata, EditAnchorData, EditAnchorError, EditAnchorErrors, EditAnchorRequest, EditAnchorResponse, EditAnchorResponse2, EditAnchorResponses, EditCallRecordData, EditCallRecordError, EditCallRecordErrors, EditCallRecordRequest, EditCallRecordResponse, EditCallRecordResponses, EditCallTranscriptData, EditCallTranscriptError, EditCallTranscriptErrors, EditCallTranscriptRequest, EditCallTranscriptResponse, EditCallTranscriptResponses, EditCommentData, EditCommentError, EditCommentErrors, EditCommentRequest, EditCommentResponse, EditCommentResponse2, EditCommentResponses, EditCrmCommentData, EditCrmCommentError, EditCrmCommentErrors, EditCrmCommentRequest, EditCrmCommentResponse, EditCrmCommentResponses, EditDocumentData, EditDocumentError, EditDocumentErrors, EditDocumentResponse, EditDocumentResponse2, EditDocumentResponses, EditDocumentServiceArgs, EditPdfAnchorRequest, EditPdfPlaceableCommentAnchorRequest, EditProjectV2Data, EditProjectV2Error, EditProjectV2Errors, EditProjectV2Response, EditProjectV2Responses, EditThreadV2Data, EditThreadV2Error, EditThreadV2Errors, EditThreadV2Response, EditThreadV2Responses, EmailFilters, EmptyResponse, EnsureCollabSurfaceData, EnsureCollabSurfaceError, EnsureCollabSurfaceErrors, EnsureCollabSurfaceRequest, EnsureCollabSurfaceResponse, EnsureCollabSurfaceResponses, EntityFilters, EntityMessageCreateData, EntityMessageCreateResponse, EntityMessageCreateResponses, EntityMessageDeleteMessageData, EntityMessageDeleteMessageResponse, EntityMessageDeleteMessageResponses, EntityMessageDeleteThreadData, EntityMessageDeleteThreadResponse, EntityMessageDeleteThreadResponses, EntityMessageEditData, EntityMessageEditResponse, EntityMessageEditResponses, EntityMessageGetMessageData, EntityMessageGetMessageResponse, EntityMessageGetMessageResponses, EntityMessageGetThreadData, EntityMessageGetThreadResponse, EntityMessageGetThreadResponses, EntityMessageLegacyData, EntityMessageLegacyResponse, EntityMessageLegacyResponses, EntityMessagePatchThreadData, EntityMessagePatchThreadResponse, EntityMessagePatchThreadResponses, EntityMessageReactData, EntityMessageReactResponse, EntityMessageReactResponses, EntityMessageReferencesData, EntityMessageReferencesResponse, EntityMessageReferencesResponses, EntityMessageTypingData, EntityMessageTypingResponse, EntityMessageTypingResponses, EntityPermission, EntityPermissionResponse, EntityReference, EntityType, ErrorResponse, EventReminderOverride, EventReminders, EventStatus, EventTime, EventTransparency, EventType, EventVisibility, ExcludedDefaultView, ExcludeDefaultViewHandlerData, ExcludeDefaultViewHandlerError, ExcludeDefaultViewHandlerErrors, ExcludeDefaultViewHandlerResponses, ExcludeDefaultViewRequest, ExportDocumentData, ExportDocumentError, ExportDocumentErrors, ExportDocumentResponse, ExportDocumentResponse2, ExportDocumentResponses, Favorite, FavoriteEntityRef, FavoritesList, FileSystemNodeWithIds, FileType, FileTypeUpdate, FolderItem, ForeignEntity, ForeignEntityFilters, GenericErrorResponse, GenericResponse, GenericSuccessResponse, GetActiveCallsData, GetActiveCallsError, GetActiveCallsErrors, GetActiveCallsResponse, GetActiveCallsResponses, GetActivityData, GetActivityError, GetActivityErrors, GetActivityResponse, GetActivityResponses, GetAttachmentReferencesData, GetAttachmentReferencesError, GetAttachmentReferencesErrors, GetAttachmentReferencesResponse, GetAttachmentReferencesResponse2, GetAttachmentReferencesResponses, GetBatchCallRecordPreviewData, GetBatchCallRecordPreviewError, GetBatchCallRecordPreviewErrors, GetBatchCallRecordPreviewRequest, GetBatchCallRecordPreviewResponse, GetBatchCallRecordPreviewResponse2, GetBatchCallRecordPreviewResponses, GetBatchChannelPreviewData, GetBatchChannelPreviewError, GetBatchChannelPreviewErrors, GetBatchChannelPreviewRequest, GetBatchChannelPreviewResponse, GetBatchChannelPreviewResponse2, GetBatchChannelPreviewResponses, GetBatchPreviewHandlerData, GetBatchPreviewHandlerError, GetBatchPreviewHandlerErrors, GetBatchPreviewHandlerResponse, GetBatchPreviewHandlerResponses, GetBatchPreviewRequest, GetBatchPreviewResponse, GetBatchProjectPreviewData, GetBatchProjectPreviewError, GetBatchProjectPreviewErrors, GetBatchProjectPreviewRequest, GetBatchProjectPreviewResponse, GetBatchProjectPreviewResponse2, GetBatchProjectPreviewResponses, GetCallRecordData, GetCallRecordError, GetCallRecordErrors, GetCallRecordResponse, GetCallRecordResponses, GetChannelAttachmentsData, GetChannelAttachmentsError, GetChannelAttachmentsErrors, GetChannelAttachmentsResponse, GetChannelAttachmentsResponses, GetChannelData, GetChannelError, GetChannelErrors, GetChannelJoinLinkData, GetChannelJoinLinkError, GetChannelJoinLinkErrors, GetChannelJoinLinkResponse, GetChannelJoinLinkResponses, GetChannelMessagesCatchUpData, GetChannelMessagesCatchUpError, GetChannelMessagesCatchUpErrors, GetChannelMessagesCatchUpResponse, GetChannelMessagesCatchUpResponses, GetChannelMessagesData, GetChannelMessagesError, GetChannelMessagesErrors, GetChannelMessagesResponse, GetChannelMessagesResponses, GetChannelParticipantsData, GetChannelParticipantsError, GetChannelParticipantsErrors, GetChannelParticipantsResponse, GetChannelParticipantsResponses, GetChannelResponse, GetChannelResponses, GetChannelsData, GetChannelsError, GetChannelsErrors, GetChannelsResponse, GetChannelsResponses, GetCollabSurfaceData, GetCollabSurfaceError, GetCollabSurfaceErrors, GetCollabSurfaceResponse, GetCollabSurfaceResponses, GetCompanyData, GetCompanyError, GetCompanyErrors, GetCompanyResponse, GetCompanyResponses, GetContactByEmailData, GetContactByEmailError, GetContactByEmailErrors, GetContactByEmailResponse, GetContactByEmailResponse2, GetContactByEmailResponses, GetContactData, GetContactError, GetContactErrors, GetContactResponse, GetContactResponses, GetCrmTeamSettingsData, GetCrmTeamSettingsError, GetCrmTeamSettingsErrors, GetCrmTeamSettingsResponse, GetCrmTeamSettingsResponses, GetDocumentAnchorsData, GetDocumentAnchorsError, GetDocumentAnchorsErrors, GetDocumentAnchorsResponse, GetDocumentAnchorsResponses, GetDocumentBranchNameData, GetDocumentBranchNameError, GetDocumentBranchNameErrors, GetDocumentBranchNameResponse, GetDocumentBranchNameResponses, GetDocumentByTeamSlugData, GetDocumentByTeamSlugError, GetDocumentByTeamSlugErrors, GetDocumentByTeamSlugResponse, GetDocumentByTeamSlugResponses, GetDocumentCommentsData, GetDocumentCommentsError, GetDocumentCommentsErrors, GetDocumentCommentsResponse, GetDocumentCommentsResponses, GetDocumentData, GetDocumentError, GetDocumentErrors, GetDocumentGithubPullRequestsData, GetDocumentGithubPullRequestsError, GetDocumentGithubPullRequestsErrors, GetDocumentGithubPullRequestsResponse, GetDocumentGithubPullRequestsResponses, GetDocumentKeyResponse, GetDocumentKeyResponseData, GetDocumentListHandlerData, GetDocumentListHandlerError, GetDocumentListHandlerErrors, GetDocumentListHandlerResponse, GetDocumentListHandlerResponses, GetDocumentListResult, GetDocumentLocationV3Data, GetDocumentLocationV3Error, GetDocumentLocationV3Errors, GetDocumentLocationV3Response, GetDocumentLocationV3Responses, GetDocumentPermissionsResponseDataV2, GetDocumentPermissionsTokenData, GetDocumentPermissionsTokenError, GetDocumentPermissionsTokenErrors, GetDocumentPermissionsTokenResponse, GetDocumentPermissionsTokenResponses, GetDocumentPermissionsV2Data, GetDocumentPermissionsV2Error, GetDocumentPermissionsV2Errors, GetDocumentPermissionsV2Response, GetDocumentPermissionsV2Responses, GetDocumentProcessingResult, GetDocumentProcessingResultData, GetDocumentProcessingResultError, GetDocumentProcessingResultErrors, GetDocumentProcessingResultResponse, GetDocumentProcessingResultResponse2, GetDocumentProcessingResultResponses, GetDocumentResponse, GetDocumentResponse2, GetDocumentResponseData, GetDocumentResponses, GetDocumentSearchResponse, GetDocumentShortIdData, GetDocumentShortIdError, GetDocumentShortIdErrors, GetDocumentShortIdResponse, GetDocumentShortIdResponses, GetDocumentsResponse, GetDocumentTeamShareData, GetDocumentTeamShareError, GetDocumentTeamShareErrors, GetDocumentTeamShareResponse, GetDocumentTeamShareResponses, GetDocumentUserAccessLevelResponse, GetDocumentVersionData, GetDocumentVersionError, GetDocumentVersionErrors, GetDocumentVersionResponse, GetDocumentVersionResponses, GetDocumentViewsHandlerData, GetDocumentViewsHandlerError, GetDocumentViewsHandlerErrors, GetDocumentViewsHandlerResponse, GetDocumentViewsHandlerResponses, GetEntityPermissionData, GetEntityPermissionErrors, GetEntityPermissionResponse, GetEntityPermissionResponses, GetForeignEntityBySourceData, GetForeignEntityBySourceError, GetForeignEntityBySourceErrors, GetForeignEntityBySourceResponse, GetForeignEntityBySourceResponses, GetForeignEntityData, GetForeignEntityError, GetForeignEntityErrors, GetForeignEntityResponse, GetForeignEntityResponses, GetHarnessPairingData, GetHarnessPairingError, GetHarnessPairingErrors, GetHarnessPairingResponse, GetHarnessPairingResponses, GetHistoryHandlerData, GetHistoryHandlerError, GetHistoryHandlerErrors, GetHistoryHandlerResponse, GetHistoryHandlerResponses, GetInitiativeData, GetInitiativeError, GetInitiativeErrors, GetInitiativeResponse, GetInitiativeResponses, GetInstructionsDocumentResponse, GetInstructionsHandlerData, GetInstructionsHandlerError, GetInstructionsHandlerErrors, GetInstructionsHandlerResponse, GetInstructionsHandlerResponses, GetItemsSoupData, GetItemsSoupError, GetItemsSoupErrors, GetItemsSoupResponse, GetItemsSoupResponses, GetLocationHandlerData, GetLocationHandlerError, GetLocationHandlerErrors, GetLocationHandlerResponse, GetLocationHandlerResponses, GetMessageWithContextData, GetMessageWithContextError, GetMessageWithContextErrors, GetMessageWithContextResponse, GetMessageWithContextResponse2, GetMessageWithContextResponses, GetOrCreateAction, GetOrCreateCallData, GetOrCreateCallError, GetOrCreateCallErrors, GetOrCreateCallResponse, GetOrCreateCallResponses, GetOrCreateChannelResponse, GetOrCreateDmData, GetOrCreateDmError, GetOrCreateDmErrors, GetOrCreateDmRequest, GetOrCreateDmResponse, GetOrCreateDmResponses, GetOrCreatePrivateData, GetOrCreatePrivateError, GetOrCreatePrivateErrors, GetOrCreatePrivateRequest, GetOrCreatePrivateResponse, GetOrCreatePrivateResponses, GetPendingProjectsHandlerData, GetPendingProjectsHandlerError, GetPendingProjectsHandlerErrors, GetPendingProjectsHandlerResponse, GetPendingProjectsHandlerResponses, GetPinsHandlerData, GetPinsHandlerError, GetPinsHandlerErrors, GetPinsHandlerResponse, GetPinsHandlerResponses, GetPinsResponse, GetProjectContentHandlerData, GetProjectContentHandlerError, GetProjectContentHandlerErrors, GetProjectContentHandlerResponse, GetProjectContentHandlerResponses, GetProjectContentResponse, GetProjectHandlerData, GetProjectHandlerError, GetProjectHandlerErrors, GetProjectHandlerResponse, GetProjectHandlerResponses, GetProjectPermissionsV2Data, GetProjectPermissionsV2Error, GetProjectPermissionsV2Errors, GetProjectPermissionsV2Response, GetProjectPermissionsV2Responses, GetProjectResponse, GetProjectResponseData, GetProjectsHandlerData, GetProjectsHandlerError, GetProjectsHandlerErrors, GetProjectsHandlerResponse, GetProjectsHandlerResponses, GetProjectsResponse, GetProjectUserAccessLevelData, GetProjectUserAccessLevelError, GetProjectUserAccessLevelErrors, GetProjectUserAccessLevelResponse, GetProjectUserAccessLevelResponses, GetReminderData, GetReminderError, GetReminderErrors, GetReminderResponse, GetReminderResponses, GetRingStatusData, GetRingStatusError, GetRingStatusErrors, GetRingStatusResponse, GetRingStatusResponses, GetSelfBotData, GetSelfBotError, GetSelfBotErrors, GetSelfBotResponse, GetSelfBotResponses, GetSelfHarnessData, GetSelfHarnessError, GetSelfHarnessErrors, GetSelfHarnessResponse, GetSelfHarnessResponses, GetSystemSkillsHandlerData, GetSystemSkillsHandlerError, GetSystemSkillsHandlerErrors, GetSystemSkillsHandlerResponse, GetSystemSkillsHandlerResponses, GetThreadRepliesData, GetThreadRepliesError, GetThreadRepliesErrors, GetThreadRepliesResponse, GetThreadRepliesResponses, GetUserDocumentsHandlerData, GetUserDocumentsHandlerError, GetUserDocumentsHandlerErrors, GetUserDocumentsHandlerResponse, GetUserDocumentsHandlerResponses, GetUserDocumentViewLocationData, GetUserDocumentViewLocationError, GetUserDocumentViewLocationErrors, GetUserDocumentViewLocationResponse, GetUserDocumentViewLocationResponses, GetUserHistoryResponse, GetViewsHandlerData, GetViewsHandlerError, GetViewsHandlerErrors, GetViewsHandlerResponse, GetViewsHandlerResponses, GetWebhookData, GetWebhookError, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GithubPullRequest, GithubPullRequestCheckRun, GithubPullRequestComment, GithubPullRequestsResponse, GroupedInitialParams, GroupedPageParams, GroupedSoupGroupPage, GroupedSoupInitialPage, GroupedSoupPage, GroupedSoupSort, HandlerData, HandlerError, HandlerErrors, HandlerResponse, HandlerResponses, Harness, HarnessAgent, HarnessId, HarnessOwner, HarnessSession, HashMap, HealthHandlerData, HealthHandlerResponse, HealthHandlerResponses, HighlightType, ImportedAuthor, InFlightTurnSummary, IngestTranscriptData, IngestTranscriptError, IngestTranscriptErrors, IngestTranscriptResponses, InitializeUserDocumentsData, InitializeUserDocumentsError, InitializeUserDocumentsErrors, InitializeUserDocumentsResponse, InitializeUserDocumentsResponses, InitiativeDetail, InitiativeId, InitiativeList, InitiativeSummary, InputReceivedMetadata, InstallSyncData, InstallSyncErrors, InteractionReason, Item, ItemWithUserAccessLevel, JobProcessingResultHandlerData, JobProcessingResultHandlerError, JobProcessingResultHandlerErrors, JobProcessingResultHandlerResponse, JobProcessingResultHandlerResponses, JoinChannelByCodeData, JoinChannelByCodeError, JoinChannelByCodeErrors, JoinChannelByCodeResponses, JoinChannelData, JoinChannelError, JoinChannelErrors, JoinChannelResponses, LatestMessage, LeaveCallResponse, LeaveChannelData, LeaveChannelError, LeaveChannelErrors, LeaveChannelResponses, LeaveOrEndCallData, LeaveOrEndCallError, LeaveOrEndCallErrors, LeaveOrEndCallResponse, LeaveOrEndCallResponses, LinkShare, ListAgentsData, ListAgentsError, ListAgentsErrors, ListAgentsResponse, ListAgentsResponses, ListBotChannelsData, ListBotChannelsError, ListBotChannelsErrors, ListBotChannelsResponse, ListBotChannelsResponses, ListCompanyContactsData, ListCompanyContactsError, ListCompanyContactsErrors, ListCompanyContactsResponse, ListCompanyContactsResponses, ListCrmCommentsData, ListCrmCommentsError, ListCrmCommentsErrors, ListCrmCommentsResponse, ListCrmCommentsResponses, ListFavoritesData, ListFavoritesError, ListFavoritesErrors, ListFavoritesResponse, ListFavoritesResponses, ListHarnessAgentsData, ListHarnessAgentsError, ListHarnessAgentsErrors, ListHarnessAgentsResponse, ListHarnessAgentsResponses, ListHarnessesData, ListHarnessesError, ListHarnessesErrors, ListHarnessesResponse, ListHarnessesResponses, ListHarnessSessionsData, ListHarnessSessionsError, ListHarnessSessionsErrors, ListHarnessSessionsResponse, ListHarnessSessionsResponses, ListInitiativesData, ListInitiativesError, ListInitiativesErrors, ListInitiativesResponse, ListInitiativesResponses, ListOccurrencesData, ListOccurrencesErrors, ListOccurrencesResponse, ListOccurrencesResponses, ListRemindersData, ListRemindersError, ListRemindersErrors, ListRemindersResponse, ListRemindersResponses, ListTeamOutOfOfficeData, ListTeamOutOfOfficeErrors, ListTeamOutOfOfficeResponse, ListTeamOutOfOfficeResponses, ListUserApiKeysData, ListUserApiKeysError, ListUserApiKeysErrors, ListUserApiKeysResponse, ListUserApiKeysResponses, ListWebhooksData, ListWebhooksError, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponse2, ListWebhooksResponses, LocationResponseData, LocationResponseV3, MacroUserIdStr, MentionPreviewsData, MentionPreviewsErrors, MentionPreviewsResponse, MentionPreviewsResponses, Mentions, Message, MessageAttachment, MessageChange, MessageCursor, MessageDirection, MessageEvent, MessageListItem, MessagePage, MessageParent, MessagePatch, MessageThread, MessageThreadPreview, MessageTimelineData, MessageTimelineQuery, MessageTimelineResponse, MessageTimelineResponses, NewAttachment, NewChannelAttachment, NewThreadAnchor, NotificationFilters, NotificationState, PairingDetails, Params, ParticipantRole, PatchBotRequest, PatchChannelData, PatchChannelError, PatchChannelErrors, PatchChannelRequest, PatchChannelResponse, PatchChannelResponses, PatchMessageData, PatchMessageError, PatchMessageErrors, PatchMessageNotificationPolicy, PatchMessageRequest, PatchMessageResponse, PatchMessageResponses, PatchProjectRequestV2, PatchThreadRequestV2, PatchViewHandlerData, PatchViewHandlerError, PatchViewHandlerErrors, PatchViewHandlerResponses, PatchWebhookData, PatchWebhookError, PatchWebhookErrors, PatchWebhookRequest, PatchWebhookResponse, PatchWebhookResponses, PdfAnchor, PdfAnchorId, PdfAnchorRequest, PdfHighlightAnchor, PdfHighlightAnchorRequest, PdfHighlightRect, PdfHighlightRectAnchorRequest, PdfPlaceableCommentAnchor, PdfPlaceableCommentAnchorRequest, PendingClaimResponse, PermanentlyDeleteDocumentData, PermanentlyDeleteDocumentError, PermanentlyDeleteDocumentErrors, PermanentlyDeleteDocumentResponse, PermanentlyDeleteDocumentResponses, PermanentlyDeleteProjectData, PermanentlyDeleteProjectError, PermanentlyDeleteProjectErrors, PermanentlyDeleteProjectResponse, PermanentlyDeleteProjectResponses, PinnedItem, PinRequest, PostActivityData, PostActivityError, PostActivityErrors, PostActivityRequest, PostActivityResponse, PostActivityResponses, PostChannelBotWebhookData, PostChannelBotWebhookError, PostChannelBotWebhookErrors, PostChannelBotWebhookResponse, PostChannelBotWebhookResponses, PostChannelMessagesData, PostChannelMessagesError, PostChannelMessagesErrors, PostChannelMessagesResponse, PostChannelMessagesResponses, PostGroupedSoupAstGroupPageRequest, PostGroupedSoupAstInitialRequest, PostGroupedSoupAstRequest, PostItemsSoupAstData, PostItemsSoupAstError, PostItemsSoupAstErrors, PostItemsSoupAstGroupedData, PostItemsSoupAstGroupedError, PostItemsSoupAstGroupedErrors, PostItemsSoupAstGroupedResponse, PostItemsSoupAstGroupedResponses, PostItemsSoupAstResponse, PostItemsSoupAstResponses, PostItemsSoupData, PostItemsSoupError, PostItemsSoupErrors, PostItemsSoupResponse, PostItemsSoupResponses, PostMessage, PostMessageData, PostMessageError, PostMessageErrors, PostMessageNotificationPolicy, PostMessageRequest, PostMessageResponse, PostMessageResponse2, PostMessageResponses, PostReactionData, PostReactionError, PostReactionErrors, PostReactionRequest, PostReactionResponse, PostReactionResponses, PostSoupAstRequest, PostSoupRequest, PostTypingData, PostTypingError, PostTypingErrors, PostTypingRequest, PostTypingResponse, PostTypingResponses, PresaveDocumentHandlerData, PresaveDocumentHandlerError, PresaveDocumentHandlerErrors, PresaveDocumentHandlerResponse, PresaveDocumentHandlerResponses, PreSaveDocumentRequest, PreSaveDocumentResponse, PreSaveDocumentResponseData, PresignedUrl, Project, ProjectDeleteResponseData, ProjectDocumentStatus, ProjectFilters, ProjectPreview, ProjectPreviewData, PropertyDefinition, PropertyFilter, PropertyInput, PropertyOwner, PropertyValue, PutCrmTeamSettingsData, PutCrmTeamSettingsError, PutCrmTeamSettingsErrors, PutCrmTeamSettingsResponse, PutCrmTeamSettingsResponses, PutCrmTeamStagesData, PutCrmTeamStagesError, PutCrmTeamStagesErrors, PutCrmTeamStagesResponse, PutCrmTeamStagesResponses, ReactionAction, ReactionInput, RecentlyDeletedData, RecentlyDeletedError, RecentlyDeletedErrors, RecentlyDeletedResponse, RecentlyDeletedResponseData, RecentlyDeletedResponses, ReferencedThread, ReferencedThreadPage, Reminder, ReminderFilters, ReminderSchedule, RemindersList, RemoveBotFromChannelByBotData, RemoveBotFromChannelByBotError, RemoveBotFromChannelByBotErrors, RemoveBotFromChannelByBotResponse, RemoveBotFromChannelByBotResponses, RemoveFavoriteByEntityData, RemoveFavoriteByEntityError, RemoveFavoriteByEntityErrors, RemoveFavoriteByEntityResponses, RemoveParticipantsData, RemoveParticipantsError, RemoveParticipantsErrors, RemoveParticipantsRequest, RemoveParticipantsResponses, RemovePinHandlerData, RemovePinHandlerError, RemovePinHandlerErrors, RemovePinHandlerResponse, RemovePinHandlerResponses, ReorderFavoritesData, ReorderFavoritesError, ReorderFavoritesErrors, ReorderFavoritesRequest, ReorderFavoritesResponses, ReorderPinRequest, ReorderPinsHandlerData, ReorderPinsHandlerError, ReorderPinsHandlerErrors, ReorderPinsHandlerResponse, ReorderPinsHandlerResponses, ReplaceCrmStagesRequest, RequestedHarnessScope, ResetCrmTeamStagesData, ResetCrmTeamStagesError, ResetCrmTeamStagesErrors, ResetCrmTeamStagesResponse, ResetCrmTeamStagesResponses, ResolveChannelMessageData, ResolveChannelMessageError, ResolveChannelMessageErrors, ResolveChannelMessageResponse, ResolveChannelMessageResponses, RevertDeleteDocumentData, RevertDeleteDocumentError, RevertDeleteDocumentErrors, RevertDeleteDocumentResponse, RevertDeleteDocumentResponses, RevertDeleteProjectData, RevertDeleteProjectError, RevertDeleteProjectErrors, RevertDeleteProjectResponse, RevertDeleteProjectResponses, RingStatus, RingStatusResponse, S3ObjectInfo, SaveBomPart, SaveDocumentHandlerData, SaveDocumentHandlerError, SaveDocumentHandlerErrors, SaveDocumentHandlerResponse, SaveDocumentHandlerResponses, SaveDocumentRequest, SaveDocumentResponse, SaveDocumentResponseData, SessionDeletedMetadata, SessionIdentity, SessionMentionedMetadata, SessionOpenedMetadata, SessionRenamedMetadata, SessionSettledMetadata, SessionStoppedMetadata, SetChannelPictureData, SetChannelPictureError, SetChannelPictureErrors, SetChannelPictureRequest, SetChannelPictureResponse, SetChannelPictureResponses, SetCompanyHiddenData, SetCompanyHiddenError, SetCompanyHiddenErrors, SetCompanyHiddenRequest, SetCompanyHiddenResponse, SetCompanyHiddenResponses, SetCompanyNameRequest, SetContactHiddenData, SetContactHiddenError, SetContactHiddenErrors, SetContactHiddenRequest, SetContactHiddenResponse, SetContactHiddenResponses, SetContactNameRequest, SetCrmCompanyNameData, SetCrmCompanyNameError, SetCrmCompanyNameErrors, SetCrmCompanyNameResponse, SetCrmCompanyNameResponses, SetCrmContactNameData, SetCrmContactNameError, SetCrmContactNameErrors, SetCrmContactNameResponse, SetCrmContactNameResponses, SetDocumentTeamShareData, SetDocumentTeamShareError, SetDocumentTeamShareErrors, SetDocumentTeamShareRequest, SetDocumentTeamShareResponse, SetDocumentTeamShareResponses, SetEmailSyncData, SetEmailSyncError, SetEmailSyncErrors, SetEmailSyncRequest, SetEmailSyncResponse, SetEmailSyncResponses, SetPropertyValue, SharedEmailFilter, SharePermissionV2, ShortIdResponse, SimpleMention, SimpleSaveData, SimpleSaveError, SimpleSaveErrors, SimpleSaveResponse, SimpleSaveResponses, SoupAgentSessionSoupPropertiesField, SoupApiItem, SoupApiSort, SoupApiSortDirection, SoupAttachment, SoupCalendarEventSoupPropertiesField, SoupCalendarEventTime, SoupCallRecordParticipant, SoupCallRecordSoupPropertiesField, SoupChannel, SoupChannelThread, SoupChatSoupPropertiesField, SoupContact, SoupCountedReaction, SoupCrmCompanySoupPropertiesField, SoupCrmDomain, SoupDocumentSoupPropertiesField, SoupDocumentSubType, SoupEmailThreadPreview, SoupEnrichedEmailThreadPreviewSoupPropertiesField, SoupForeignEntity, SoupItem, SoupLabel, SoupLabelListVisibility, SoupLabelType, SoupMessageAttachment, SoupMessageListVisibility, SoupMessageSender, SoupMessageSenderType, SoupPage, SoupProjectSoupPropertiesField, SoupPropertiesField, SoupProperty, SoupReminderReference, SoupReminderSchedule, SoupReminderSoupPropertiesField, SoupThreadInfo, SoupThreadReply, StarterDocumentsResponse, StreamEventsData, StreamEventsError, StreamEventsErrors, StreamEventsResponse, StreamEventsResponses, String, SuccessResponse, SurfaceState, SyncServiceVersionId, SystemSkillSummary, TagFilterMode, TaskFilters, TeamOutOfOfficeItem, TeamOutOfOfficeResponse, TeamRole, Thread, ThreadAnchor, ThreadOrigin, ThreadPatch, ThreadResponse, ThreadState, ToggleShareWithTeamData, ToggleShareWithTeamError, ToggleShareWithTeamErrors, ToggleShareWithTeamResponse, ToggleShareWithTeamResponses, TranscriptSegmentRequest, TurnEndedMetadata, TurnStartedMetadata, TurnSummary, TypedSuccessResponse, TypedSuccessResponseGetDocumentResponseData, TypingAction, TypingInput, UnassignInitiativeTaskData, UnassignInitiativeTaskError, UnassignInitiativeTaskErrors, UnassignInitiativeTaskResponse, UnassignInitiativeTaskResponses, UnthreadedPdfUuidRequest, UpdateAgentData, UpdateAgentError, UpdateAgentErrors, UpdateAgentRequest, UpdateAgentResponse, UpdateAgentResponses, UpdateChannelSharePermission, UpdateCrmTeamSettingsRequest, UpdateInitiativeData, UpdateInitiativeError, UpdateInitiativeErrors, UpdateInitiativeRequest, UpdateInitiativeResponse, UpdateInitiativeResponses, UpdateOperation, UpdateReminderData, UpdateReminderError, UpdateReminderErrors, UpdateReminderRequest, UpdateReminderResponse, UpdateReminderResponses, UpdateSharePermissionRequestV2, UploadDocumentStatus, UploadExtractFolderHandlerData, UploadExtractFolderHandlerError, UploadExtractFolderHandlerErrors, UploadExtractFolderHandlerResponse, UploadExtractFolderHandlerResponses, UploadExtractFolderRequest, UploadFolderHandlerData, UploadFolderHandlerError, UploadFolderHandlerErrors, UploadFolderHandlerResponse, UploadFolderHandlerResponses, UploadFolderRequest, UpsertHistoryHandlerData, UpsertHistoryHandlerError, UpsertHistoryHandlerErrors, UpsertHistoryHandlerResponse, UpsertHistoryHandlerResponses, UpsertUserDocumentViewLocationData, UpsertUserDocumentViewLocationError, UpsertUserDocumentViewLocationErrors, UpsertUserDocumentViewLocationRequest, UpsertUserDocumentViewLocationResponse, UpsertUserDocumentViewLocationResponses, UserApiKeyId, UserApiKeyInfo, UserApiKeysList, UserDocumentsResponse, UserDocumentViewLocation, UserDocumentViewLocationResponse, UserPinsResponse, UserViewsResponse, ValidateDocumentPermissionsTokenData, ValidateDocumentPermissionsTokenError, ValidateDocumentPermissionsTokenErrors, ValidateDocumentPermissionsTokenResponse, ValidateDocumentPermissionsTokenResponses, ValidateWebhookData, ValidateWebhookError, ValidateWebhookErrors, ValidateWebhookResponse, ValidateWebhookResponse2, ValidateWebhookResponses, Vec, View, ViewPatch, ViewsResponse, WaitingForInputMetadata, Webhook, WebhookEvent, WebhookFilter, WebhookScope, WebhookStatus, WebhookValidationTestEvent, WithCallId, WithChannelId, WithDocumentId, WithProjectId } from './types.gen';
+export type { AccessLevel, ActiveCallsResponse, ActiveCallSummary, ActivityType, AddFavoriteData, AddFavoriteError, AddFavoriteErrors, AddFavoriteRequest, AddFavoriteResponse, AddFavoriteResponses, AddParticipantsData, AddParticipantsError, AddParticipantsErrors, AddParticipantsRequest, AddParticipantsResponses, AddPinHandlerData, AddPinHandlerError, AddPinHandlerErrors, AddPinHandlerResponse, AddPinHandlerResponses, AddPinRequest, Agent, AgentActionId, AgentChannelScope, AgentMcpServer, AgentMcpServers, AgentSessionFilters, AgentSessionLifecycleEvent, Anchor, AnchorId, AnchorRequest, AnchorResponse, AnnotationIncrementalUpdate, ApiActivity, ApiAttachmentChannelReference, ApiAttachmentEntityReference, ApiAttachmentGenericReference, ApiChannelAttachment, ApiChannelAttachmentsPage, ApiChannelContextMessage, ApiChannelDetail, ApiChannelListMessage, ApiChannelListPage, ApiChannelListParticipant, ApiChannelListType, ApiChannelMessage, ApiChannelMessageKind, ApiChannelMessagesPage, ApiChannelParticipant, ApiChannelWithLatest, ApiCountedReaction, ApiEntityFilterAst, ApiGroupByField, ApiGroupMeta, ApiMessageAttachment, ApiMessageSender, ApiMessageSenderType, ApiParticipantListRole, ApiParticipantRole, ApiPropertyEntityType, ApiResolvedChannelMessage, ApiThreadInfo, ApiThreadReply, ApproveHarnessPairingData, ApproveHarnessPairingError, ApproveHarnessPairingErrors, ApproveHarnessPairingResponse, ApproveHarnessPairingResponses, ApprovePairingRequest, AssignInitiativeTasksData, AssignInitiativeTasksError, AssignInitiativeTasksErrors, AssignInitiativeTasksResponse, AssignInitiativeTasksResponses, AssignTasksRequest, AssignTasksResponse, AssignTasksResult, AssignTaskStatus, AttachmentChange, AttendeeResponseStatus, BasicDocument, BasicDocumentSubType, BomPart, Bot, BotChannel, BotChannelType, BotId, BotKind, BotOwner, BotSenderProfile, BotToken, BranchNameResponse, BTreeMap, BulkWakeupRequest, BulkWakeupResponse, BulkWakeupSyncServiceDocumentsData, BulkWakeupSyncServiceDocumentsErrors, BulkWakeupSyncServiceDocumentsResponse, BulkWakeupSyncServiceDocumentsResponses, CalendarAttendee, CalendarEvent, CalendarEventFilters, CalendarEventSourceContent, CalendarMentionEvent, CalendarMentionPreviewItem, CalendarMentionPreviewKind, CalendarMentionPreviewRequest, CalendarMentionPreviewRequestItem, CalendarMentionPreviewResponse, CalendarOccurrence, CalendarOccurrenceItem, CalendarOccurrenceResponse, CalendarSyncStatus, CallActiveResponse, CallFilters, CallRecord, CallRecordParticipant, CallRecordPreview, CallRecordPreviewData, CallRecordTranscriptSegment, CallStatus, CallTokenResponse, CallWebhookData, CallWebhookError, CallWebhookErrors, CallWebhookResponses, Channel, ChannelCreatedMetadata, ChannelDeletedMetadata, ChannelEventAttachment, ChannelFilters, ChannelJoinCodeResponse, ChannelMentionedMetadata, ChannelMessage, ChannelMessageAttachmentCreatedMetadata, ChannelMessageAttachmentRemovedMetadata, ChannelMessageDeletedMetadata, ChannelMessageFilters, ChannelMessagePatchedMetadata, ChannelMessagePostedMetadata, ChannelParticipant, ChannelParticipantAddedMetadata, ChannelParticipantRemovedMetadata, ChannelPreview, ChannelPreviewData, ChannelSender, ChannelSharePermission, ChannelThreadFilters, ChannelTopicEvent, ChannelType, ChannelUpdatedMetadata, ChannelWebhookRequest, ChannelWebhookResponse, ChannelWithParticipants, Chat, ChatFilters, CheckActiveCallData, CheckActiveCallError, CheckActiveCallErrors, CheckActiveCallResponse, CheckActiveCallResponses, ClaimedPairing, ClaimHarnessPairingData, ClaimHarnessPairingError, ClaimHarnessPairingErrors, ClaimHarnessPairingResponse, ClaimHarnessPairingResponses, ClaimPairingRequest, ClientOptions, CloudStorageItemType, CollabSurfaceResponse, CollabSurfaceTokenResponse, Comment, CommentThread, ConferenceProvider, CopyDocumentData, CopyDocumentError, CopyDocumentErrors, CopyDocumentQueryParams, CopyDocumentRequest, CopyDocumentResponse, CopyDocumentResponse2, CopyDocumentResponses, CountedReaction, CreateAgentData, CreateAgentError, CreateAgentErrors, CreateAgentRequest, CreateAgentResponse, CreateAgentResponses, CreateAnchorData, CreateAnchorError, CreateAnchorErrors, CreateAnchorResponse, CreateAnchorResponses, CreateBotRequest, CreateBulkDocumentResponse, CreateBulkDocumentResponseData, CreateChannelData, CreateChannelError, CreateChannelErrors, CreateChannelRequest, CreateChannelResponse, CreateChannelResponse2, CreateChannelResponses, CreateChannelScopedBotData, CreateChannelScopedBotError, CreateChannelScopedBotErrors, CreateChannelScopedBotRequest, CreateChannelScopedBotResponse, CreateChannelScopedBotResponse2, CreateChannelScopedBotResponses, CreateCollabSurfaceTokenData, CreateCollabSurfaceTokenError, CreateCollabSurfaceTokenErrors, CreateCollabSurfaceTokenResponse, CreateCollabSurfaceTokenResponses, CreateCommentData, CreateCommentError, CreateCommentErrors, CreateCommentRequest, CreateCommentResponse, CreateCommentResponse2, CreateCommentResponses, CreateCrmCommentData, CreateCrmCommentError, CreateCrmCommentErrors, CreateCrmCommentRequest, CreateCrmCommentResponse, CreateCrmCommentResponses, CreateCrmCompanyData, CreateCrmCompanyError, CreateCrmCompanyErrors, CreateCrmCompanyRequest, CreateCrmCompanyResponse, CreateCrmCompanyResponses, CreateCrmContactData, CreateCrmContactError, CreateCrmContactErrors, CreateCrmContactRequest, CreateCrmContactResponse, CreateCrmContactResponses, CreateDocumentData, CreateDocumentError, CreateDocumentErrors, CreateDocumentRequest, CreateDocumentResponse, CreateDocumentResponseData, CreateDocumentResponses, CreatedPairing, CreatedUserApiKey, CreateEntityMentionData, CreateEntityMentionError, CreateEntityMentionErrors, CreateEntityMentionRequest, CreateEntityMentionResponse, CreateEntityMentionResponse2, CreateEntityMentionResponses, CreateHarnessPairingData, CreateHarnessPairingError, CreateHarnessPairingErrors, CreateHarnessPairingResponse, CreateHarnessPairingResponses, CreateInitiativeData, CreateInitiativeError, CreateInitiativeErrors, CreateInitiativeRequest, CreateInitiativeResponse, CreateInitiativeResponses, CreateInstructionsDocumentResponse, CreateInstructionsHandlerData, CreateInstructionsHandlerError, CreateInstructionsHandlerErrors, CreateInstructionsHandlerResponse, CreateInstructionsHandlerResponses, CreateMarkdownDocumentRequest, CreateMarkdownDocumentResponse, CreateMarkdownHandlerData, CreateMarkdownHandlerError, CreateMarkdownHandlerErrors, CreateMarkdownHandlerResponse, CreateMarkdownHandlerResponses, CreatePairingRequest, CreateProjectHandlerData, CreateProjectHandlerError, CreateProjectHandlerErrors, CreateProjectHandlerResponse, CreateProjectHandlerResponses, CreateProjectRequest, CreateProjectResponse, CreateReminderData, CreateReminderError, CreateReminderErrors, CreateReminderRequest, CreateReminderResponse, CreateReminderResponses, CreateSkillHandlerData, CreateSkillHandlerError, CreateSkillHandlerErrors, CreateSkillHandlerResponse, CreateSkillHandlerResponses, CreateSkillRequest, CreateSkillResponse, CreateSnippetHandlerData, CreateSnippetHandlerError, CreateSnippetHandlerErrors, CreateSnippetHandlerResponse, CreateSnippetHandlerResponses, CreateSnippetRequest, CreateSnippetResponse, CreateTaskHandlerData, CreateTaskHandlerError, CreateTaskHandlerErrors, CreateTaskHandlerResponse, CreateTaskHandlerResponses, CreateTaskRequest, CreateTaskResponse, CreateUnthreadedAnchorRequest, CreateUnthreadedAnchorResponse, CreateUnthreadedPdfAnchorRequest, CreateUserApiKeyData, CreateUserApiKeyError, CreateUserApiKeyErrors, CreateUserApiKeyRequest, CreateUserApiKeyResponse, CreateUserApiKeyResponses, CreateViewHandlerData, CreateViewHandlerError, CreateViewHandlerErrors, CreateViewHandlerResponse, CreateViewHandlerResponses, CreateViewRequest, CreateWebhookData, CreateWebhookError, CreateWebhookErrors, CreateWebhookRequest, CreateWebhookResponse, CreateWebhookResponse2, CreateWebhookResponses, CrmComment, CrmCommentEntityType, CrmCommentThread, CrmCompanyFilters, CrmCompanyResponse, CrmContactResponse, CrmDomainResponse, CrmPermissionRole, CrmStageInput, CrmStageResponse, CrmStagesResponse, CrmTeamSettingsResponse, CrmThread, CustomSpeakerAssignment, DataType, DeleteAnchorData, DeleteAnchorError, DeleteAnchorErrors, DeleteAnchorInfo, DeleteAnchorResponse, DeleteAnchorResponses, DeleteCallRecordData, DeleteCallRecordError, DeleteCallRecordErrors, DeleteCallRecordResponse, DeleteCallRecordResponses, DeleteChannelData, DeleteChannelError, DeleteChannelErrors, DeleteChannelResponse, DeleteChannelResponses, DeleteCollabSurfaceData, DeleteCollabSurfaceError, DeleteCollabSurfaceErrors, DeleteCollabSurfaceResponse, DeleteCollabSurfaceResponses, DeleteCommentData, DeleteCommentError, DeleteCommentErrors, DeleteCommentRequest, DeleteCommentResponse, DeleteCommentResponse2, DeleteCommentResponses, DeleteCrmCommentData, DeleteCrmCommentError, DeleteCrmCommentErrors, DeleteCrmCommentResponse, DeleteCrmCommentResponses, DeleteCrmCommentResult, DeleteDocumentData, DeleteDocumentError, DeleteDocumentErrors, DeleteDocumentResponse, DeleteDocumentResponses, DeleteEntityMentionData, DeleteEntityMentionError, DeleteEntityMentionErrors, DeleteEntityMentionResponse, DeleteEntityMentionResponse2, DeleteEntityMentionResponses, DeleteHarnessData, DeleteHarnessError, DeleteHarnessErrors, DeleteHarnessResponse, DeleteHarnessResponses, DeleteHistoryHandlerData, DeleteHistoryHandlerError, DeleteHistoryHandlerErrors, DeleteHistoryHandlerResponse, DeleteHistoryHandlerResponses, DeleteInitiativeData, DeleteInitiativeError, DeleteInitiativeErrors, DeleteInitiativeResponse, DeleteInitiativeResponses, DeleteMessageData, DeleteMessageError, DeleteMessageErrors, DeleteMessageQuery, DeleteMessageResponse, DeleteMessageResponses, DeleteProjectHandlerData, DeleteProjectHandlerError, DeleteProjectHandlerErrors, DeleteProjectHandlerResponse, DeleteProjectHandlerResponses, DeleteReminderData, DeleteReminderError, DeleteReminderErrors, DeleteReminderResponse, DeleteReminderResponses, DeleteSelfHarnessData, DeleteSelfHarnessError, DeleteSelfHarnessErrors, DeleteSelfHarnessResponse, DeleteSelfHarnessResponses, DeleteThreadInfo, DeleteUnthreadedAnchorRequest, DeleteUnthreadedAnchorResponse, DeleteUnthreadedPdfAnchorRequest, DeleteUserApiKeyData, DeleteUserApiKeyError, DeleteUserApiKeyErrors, DeleteUserApiKeyResponse, DeleteUserApiKeyResponses, DeleteUserDocumentViewLocationData, DeleteUserDocumentViewLocationError, DeleteUserDocumentViewLocationErrors, DeleteUserDocumentViewLocationResponse, DeleteUserDocumentViewLocationResponses, DeleteViewHandlerData, DeleteViewHandlerError, DeleteViewHandlerErrors, DeleteViewHandlerResponses, DeleteWebhookData, DeleteWebhookError, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DescriptionDocumentId, DocumentBasic, DocumentContent, DocumentContentLocation, DocumentContentState, DocumentContentUploadedMetadata, DocumentCopiedMetadata, DocumentCreatedMetadata, DocumentDeletedMetadata, DocumentFilters, DocumentId, DocumentInteractionMetadata, DocumentMetadata, DocumentMetadataWithContent, DocumentPermissionsToken, DocumentPermissionsTokenRequest, DocumentPermissionsTokenResponse, DocumentPreview, DocumentPreviewData, DocumentPreviewDataSubType, DocumentPurgedMetadata, DocumentResponse, DocumentResponseMetadata, DocumentResponseMetadataWithContent, DocumentStorageServiceApiVersion, DocumentSubType, DocumentSyncContentUpdatedMetadata, DocumentTeamShareResponse, DocumentTopicEvent, DocumentUpdatedMetadata, EditAnchorData, EditAnchorError, EditAnchorErrors, EditAnchorRequest, EditAnchorResponse, EditAnchorResponse2, EditAnchorResponses, EditCallRecordData, EditCallRecordError, EditCallRecordErrors, EditCallRecordRequest, EditCallRecordResponse, EditCallRecordResponses, EditCallTranscriptData, EditCallTranscriptError, EditCallTranscriptErrors, EditCallTranscriptRequest, EditCallTranscriptResponse, EditCallTranscriptResponses, EditCommentData, EditCommentError, EditCommentErrors, EditCommentRequest, EditCommentResponse, EditCommentResponse2, EditCommentResponses, EditCrmCommentData, EditCrmCommentError, EditCrmCommentErrors, EditCrmCommentRequest, EditCrmCommentResponse, EditCrmCommentResponses, EditDocumentData, EditDocumentError, EditDocumentErrors, EditDocumentResponse, EditDocumentResponse2, EditDocumentResponses, EditDocumentServiceArgs, EditPdfAnchorRequest, EditPdfPlaceableCommentAnchorRequest, EditProjectV2Data, EditProjectV2Error, EditProjectV2Errors, EditProjectV2Response, EditProjectV2Responses, EditThreadV2Data, EditThreadV2Error, EditThreadV2Errors, EditThreadV2Response, EditThreadV2Responses, EmailFilters, EmptyResponse, EnsureCollabSurfaceData, EnsureCollabSurfaceError, EnsureCollabSurfaceErrors, EnsureCollabSurfaceRequest, EnsureCollabSurfaceResponse, EnsureCollabSurfaceResponses, EntityFilters, EntityMessageCreateData, EntityMessageCreateResponse, EntityMessageCreateResponses, EntityMessageDeleteMessageData, EntityMessageDeleteMessageResponse, EntityMessageDeleteMessageResponses, EntityMessageDeleteThreadData, EntityMessageDeleteThreadResponse, EntityMessageDeleteThreadResponses, EntityMessageEditData, EntityMessageEditResponse, EntityMessageEditResponses, EntityMessageGetMessageData, EntityMessageGetMessageResponse, EntityMessageGetMessageResponses, EntityMessageGetThreadData, EntityMessageGetThreadResponse, EntityMessageGetThreadResponses, EntityMessageLegacyData, EntityMessageLegacyResponse, EntityMessageLegacyResponses, EntityMessagePatchThreadData, EntityMessagePatchThreadResponse, EntityMessagePatchThreadResponses, EntityMessageReactData, EntityMessageReactResponse, EntityMessageReactResponses, EntityMessageReferencesData, EntityMessageReferencesResponse, EntityMessageReferencesResponses, EntityMessageTypingData, EntityMessageTypingResponse, EntityMessageTypingResponses, EntityPermission, EntityPermissionResponse, EntityReference, EntityType, ErrorResponse, EventReminderOverride, EventReminders, EventStatus, EventTime, EventTransparency, EventType, EventVisibility, ExcludedDefaultView, ExcludeDefaultViewHandlerData, ExcludeDefaultViewHandlerError, ExcludeDefaultViewHandlerErrors, ExcludeDefaultViewHandlerResponses, ExcludeDefaultViewRequest, ExportDocumentData, ExportDocumentError, ExportDocumentErrors, ExportDocumentResponse, ExportDocumentResponse2, ExportDocumentResponses, Favorite, FavoriteEntityRef, FavoritesList, FileSystemNodeWithIds, FileType, FileTypeUpdate, FolderItem, ForeignEntity, ForeignEntityFilters, GenericErrorResponse, GenericResponse, GenericSuccessResponse, GetActiveCallsData, GetActiveCallsError, GetActiveCallsErrors, GetActiveCallsResponse, GetActiveCallsResponses, GetActivityData, GetActivityError, GetActivityErrors, GetActivityResponse, GetActivityResponses, GetAttachmentReferencesData, GetAttachmentReferencesError, GetAttachmentReferencesErrors, GetAttachmentReferencesResponse, GetAttachmentReferencesResponse2, GetAttachmentReferencesResponses, GetBatchCallRecordPreviewData, GetBatchCallRecordPreviewError, GetBatchCallRecordPreviewErrors, GetBatchCallRecordPreviewRequest, GetBatchCallRecordPreviewResponse, GetBatchCallRecordPreviewResponse2, GetBatchCallRecordPreviewResponses, GetBatchChannelPreviewData, GetBatchChannelPreviewError, GetBatchChannelPreviewErrors, GetBatchChannelPreviewRequest, GetBatchChannelPreviewResponse, GetBatchChannelPreviewResponse2, GetBatchChannelPreviewResponses, GetBatchPreviewHandlerData, GetBatchPreviewHandlerError, GetBatchPreviewHandlerErrors, GetBatchPreviewHandlerResponse, GetBatchPreviewHandlerResponses, GetBatchPreviewRequest, GetBatchPreviewResponse, GetBatchProjectPreviewData, GetBatchProjectPreviewError, GetBatchProjectPreviewErrors, GetBatchProjectPreviewRequest, GetBatchProjectPreviewResponse, GetBatchProjectPreviewResponse2, GetBatchProjectPreviewResponses, GetCallRecordData, GetCallRecordError, GetCallRecordErrors, GetCallRecordResponse, GetCallRecordResponses, GetChannelAttachmentsData, GetChannelAttachmentsError, GetChannelAttachmentsErrors, GetChannelAttachmentsResponse, GetChannelAttachmentsResponses, GetChannelData, GetChannelError, GetChannelErrors, GetChannelJoinLinkData, GetChannelJoinLinkError, GetChannelJoinLinkErrors, GetChannelJoinLinkResponse, GetChannelJoinLinkResponses, GetChannelMessagesCatchUpData, GetChannelMessagesCatchUpError, GetChannelMessagesCatchUpErrors, GetChannelMessagesCatchUpResponse, GetChannelMessagesCatchUpResponses, GetChannelMessagesData, GetChannelMessagesError, GetChannelMessagesErrors, GetChannelMessagesResponse, GetChannelMessagesResponses, GetChannelParticipantsData, GetChannelParticipantsError, GetChannelParticipantsErrors, GetChannelParticipantsResponse, GetChannelParticipantsResponses, GetChannelResponse, GetChannelResponses, GetChannelsData, GetChannelsError, GetChannelsErrors, GetChannelsResponse, GetChannelsResponses, GetCollabSurfaceData, GetCollabSurfaceError, GetCollabSurfaceErrors, GetCollabSurfaceResponse, GetCollabSurfaceResponses, GetCompanyData, GetCompanyError, GetCompanyErrors, GetCompanyResponse, GetCompanyResponses, GetContactByEmailData, GetContactByEmailError, GetContactByEmailErrors, GetContactByEmailResponse, GetContactByEmailResponse2, GetContactByEmailResponses, GetContactData, GetContactError, GetContactErrors, GetContactResponse, GetContactResponses, GetCrmTeamSettingsData, GetCrmTeamSettingsError, GetCrmTeamSettingsErrors, GetCrmTeamSettingsResponse, GetCrmTeamSettingsResponses, GetDocumentAnchorsData, GetDocumentAnchorsError, GetDocumentAnchorsErrors, GetDocumentAnchorsResponse, GetDocumentAnchorsResponses, GetDocumentBranchNameData, GetDocumentBranchNameError, GetDocumentBranchNameErrors, GetDocumentBranchNameResponse, GetDocumentBranchNameResponses, GetDocumentByTeamSlugData, GetDocumentByTeamSlugError, GetDocumentByTeamSlugErrors, GetDocumentByTeamSlugResponse, GetDocumentByTeamSlugResponses, GetDocumentCommentsData, GetDocumentCommentsError, GetDocumentCommentsErrors, GetDocumentCommentsResponse, GetDocumentCommentsResponses, GetDocumentData, GetDocumentError, GetDocumentErrors, GetDocumentGithubPullRequestsData, GetDocumentGithubPullRequestsError, GetDocumentGithubPullRequestsErrors, GetDocumentGithubPullRequestsResponse, GetDocumentGithubPullRequestsResponses, GetDocumentKeyResponse, GetDocumentKeyResponseData, GetDocumentListHandlerData, GetDocumentListHandlerError, GetDocumentListHandlerErrors, GetDocumentListHandlerResponse, GetDocumentListHandlerResponses, GetDocumentListResult, GetDocumentLocationV3Data, GetDocumentLocationV3Error, GetDocumentLocationV3Errors, GetDocumentLocationV3Response, GetDocumentLocationV3Responses, GetDocumentPermissionsResponseDataV2, GetDocumentPermissionsTokenData, GetDocumentPermissionsTokenError, GetDocumentPermissionsTokenErrors, GetDocumentPermissionsTokenResponse, GetDocumentPermissionsTokenResponses, GetDocumentPermissionsV2Data, GetDocumentPermissionsV2Error, GetDocumentPermissionsV2Errors, GetDocumentPermissionsV2Response, GetDocumentPermissionsV2Responses, GetDocumentProcessingResult, GetDocumentProcessingResultData, GetDocumentProcessingResultError, GetDocumentProcessingResultErrors, GetDocumentProcessingResultResponse, GetDocumentProcessingResultResponse2, GetDocumentProcessingResultResponses, GetDocumentResponse, GetDocumentResponse2, GetDocumentResponseData, GetDocumentResponses, GetDocumentSearchResponse, GetDocumentShortIdData, GetDocumentShortIdError, GetDocumentShortIdErrors, GetDocumentShortIdResponse, GetDocumentShortIdResponses, GetDocumentsResponse, GetDocumentTeamShareData, GetDocumentTeamShareError, GetDocumentTeamShareErrors, GetDocumentTeamShareResponse, GetDocumentTeamShareResponses, GetDocumentUserAccessLevelResponse, GetDocumentVersionData, GetDocumentVersionError, GetDocumentVersionErrors, GetDocumentVersionResponse, GetDocumentVersionResponses, GetDocumentViewsHandlerData, GetDocumentViewsHandlerError, GetDocumentViewsHandlerErrors, GetDocumentViewsHandlerResponse, GetDocumentViewsHandlerResponses, GetEntityPermissionData, GetEntityPermissionErrors, GetEntityPermissionResponse, GetEntityPermissionResponses, GetForeignEntityBySourceData, GetForeignEntityBySourceError, GetForeignEntityBySourceErrors, GetForeignEntityBySourceResponse, GetForeignEntityBySourceResponses, GetForeignEntityData, GetForeignEntityError, GetForeignEntityErrors, GetForeignEntityResponse, GetForeignEntityResponses, GetHarnessPairingData, GetHarnessPairingError, GetHarnessPairingErrors, GetHarnessPairingResponse, GetHarnessPairingResponses, GetHistoryHandlerData, GetHistoryHandlerError, GetHistoryHandlerErrors, GetHistoryHandlerResponse, GetHistoryHandlerResponses, GetInitiativeData, GetInitiativeError, GetInitiativeErrors, GetInitiativeResponse, GetInitiativeResponses, GetInstructionsDocumentResponse, GetInstructionsHandlerData, GetInstructionsHandlerError, GetInstructionsHandlerErrors, GetInstructionsHandlerResponse, GetInstructionsHandlerResponses, GetItemsSoupData, GetItemsSoupError, GetItemsSoupErrors, GetItemsSoupResponse, GetItemsSoupResponses, GetLocationHandlerData, GetLocationHandlerError, GetLocationHandlerErrors, GetLocationHandlerResponse, GetLocationHandlerResponses, GetMessageWithContextData, GetMessageWithContextError, GetMessageWithContextErrors, GetMessageWithContextResponse, GetMessageWithContextResponse2, GetMessageWithContextResponses, GetOrCreateAction, GetOrCreateCallData, GetOrCreateCallError, GetOrCreateCallErrors, GetOrCreateCallResponse, GetOrCreateCallResponses, GetOrCreateChannelResponse, GetOrCreateDmData, GetOrCreateDmError, GetOrCreateDmErrors, GetOrCreateDmRequest, GetOrCreateDmResponse, GetOrCreateDmResponses, GetOrCreatePrivateData, GetOrCreatePrivateError, GetOrCreatePrivateErrors, GetOrCreatePrivateRequest, GetOrCreatePrivateResponse, GetOrCreatePrivateResponses, GetPendingProjectsHandlerData, GetPendingProjectsHandlerError, GetPendingProjectsHandlerErrors, GetPendingProjectsHandlerResponse, GetPendingProjectsHandlerResponses, GetPinsHandlerData, GetPinsHandlerError, GetPinsHandlerErrors, GetPinsHandlerResponse, GetPinsHandlerResponses, GetPinsResponse, GetProjectContentHandlerData, GetProjectContentHandlerError, GetProjectContentHandlerErrors, GetProjectContentHandlerResponse, GetProjectContentHandlerResponses, GetProjectContentResponse, GetProjectHandlerData, GetProjectHandlerError, GetProjectHandlerErrors, GetProjectHandlerResponse, GetProjectHandlerResponses, GetProjectPermissionsV2Data, GetProjectPermissionsV2Error, GetProjectPermissionsV2Errors, GetProjectPermissionsV2Response, GetProjectPermissionsV2Responses, GetProjectResponse, GetProjectResponseData, GetProjectsHandlerData, GetProjectsHandlerError, GetProjectsHandlerErrors, GetProjectsHandlerResponse, GetProjectsHandlerResponses, GetProjectsResponse, GetProjectUserAccessLevelData, GetProjectUserAccessLevelError, GetProjectUserAccessLevelErrors, GetProjectUserAccessLevelResponse, GetProjectUserAccessLevelResponses, GetReminderData, GetReminderError, GetReminderErrors, GetReminderResponse, GetReminderResponses, GetRingStatusData, GetRingStatusError, GetRingStatusErrors, GetRingStatusResponse, GetRingStatusResponses, GetSelfBotData, GetSelfBotError, GetSelfBotErrors, GetSelfBotResponse, GetSelfBotResponses, GetSelfHarnessData, GetSelfHarnessError, GetSelfHarnessErrors, GetSelfHarnessResponse, GetSelfHarnessResponses, GetSystemSkillsHandlerData, GetSystemSkillsHandlerError, GetSystemSkillsHandlerErrors, GetSystemSkillsHandlerResponse, GetSystemSkillsHandlerResponses, GetThreadRepliesData, GetThreadRepliesError, GetThreadRepliesErrors, GetThreadRepliesResponse, GetThreadRepliesResponses, GetUserDocumentsHandlerData, GetUserDocumentsHandlerError, GetUserDocumentsHandlerErrors, GetUserDocumentsHandlerResponse, GetUserDocumentsHandlerResponses, GetUserDocumentViewLocationData, GetUserDocumentViewLocationError, GetUserDocumentViewLocationErrors, GetUserDocumentViewLocationResponse, GetUserDocumentViewLocationResponses, GetUserHistoryResponse, GetViewsHandlerData, GetViewsHandlerError, GetViewsHandlerErrors, GetViewsHandlerResponse, GetViewsHandlerResponses, GetWebhookData, GetWebhookError, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GithubPullRequest, GithubPullRequestCheckRun, GithubPullRequestComment, GithubPullRequestsResponse, GroupedInitialParams, GroupedPageParams, GroupedSoupGroupPage, GroupedSoupInitialPage, GroupedSoupPage, GroupedSoupSort, HandlerData, HandlerError, HandlerErrors, HandlerResponse, HandlerResponses, Harness, HarnessAgent, HarnessId, HarnessOwner, HarnessSession, HashMap, HealthHandlerData, HealthHandlerResponse, HealthHandlerResponses, HighlightType, ImportedAuthor, InFlightTurnSummary, IngestTranscriptData, IngestTranscriptError, IngestTranscriptErrors, IngestTranscriptResponses, InitializeUserDocumentsData, InitializeUserDocumentsError, InitializeUserDocumentsErrors, InitializeUserDocumentsResponse, InitializeUserDocumentsResponses, InitiativeDetail, InitiativeId, InitiativeList, InitiativeSummary, InputReceivedMetadata, InstallSyncData, InstallSyncErrors, InteractionReason, Item, ItemWithUserAccessLevel, JobProcessingResultHandlerData, JobProcessingResultHandlerError, JobProcessingResultHandlerErrors, JobProcessingResultHandlerResponse, JobProcessingResultHandlerResponses, JoinChannelByCodeData, JoinChannelByCodeError, JoinChannelByCodeErrors, JoinChannelByCodeResponses, JoinChannelData, JoinChannelError, JoinChannelErrors, JoinChannelResponses, LatestMessage, LeaveCallResponse, LeaveChannelData, LeaveChannelError, LeaveChannelErrors, LeaveChannelResponses, LeaveOrEndCallData, LeaveOrEndCallError, LeaveOrEndCallErrors, LeaveOrEndCallResponse, LeaveOrEndCallResponses, LinkShare, ListAgentsData, ListAgentsError, ListAgentsErrors, ListAgentsResponse, ListAgentsResponses, ListBotChannelsData, ListBotChannelsError, ListBotChannelsErrors, ListBotChannelsResponse, ListBotChannelsResponses, ListCompanyContactsData, ListCompanyContactsError, ListCompanyContactsErrors, ListCompanyContactsResponse, ListCompanyContactsResponses, ListCrmCommentsData, ListCrmCommentsError, ListCrmCommentsErrors, ListCrmCommentsResponse, ListCrmCommentsResponses, ListFavoritesData, ListFavoritesError, ListFavoritesErrors, ListFavoritesResponse, ListFavoritesResponses, ListHarnessAgentsData, ListHarnessAgentsError, ListHarnessAgentsErrors, ListHarnessAgentsResponse, ListHarnessAgentsResponses, ListHarnessesData, ListHarnessesError, ListHarnessesErrors, ListHarnessesResponse, ListHarnessesResponses, ListHarnessSessionsData, ListHarnessSessionsError, ListHarnessSessionsErrors, ListHarnessSessionsResponse, ListHarnessSessionsResponses, ListInitiativesData, ListInitiativesError, ListInitiativesErrors, ListInitiativesResponse, ListInitiativesResponses, ListOccurrencesData, ListOccurrencesErrors, ListOccurrencesResponse, ListOccurrencesResponses, ListRemindersData, ListRemindersError, ListRemindersErrors, ListRemindersResponse, ListRemindersResponses, ListTeamOutOfOfficeData, ListTeamOutOfOfficeErrors, ListTeamOutOfOfficeResponse, ListTeamOutOfOfficeResponses, ListUserApiKeysData, ListUserApiKeysError, ListUserApiKeysErrors, ListUserApiKeysResponse, ListUserApiKeysResponses, ListWebhooksData, ListWebhooksError, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponse2, ListWebhooksResponses, LocationResponseData, LocationResponseV3, MacroUserIdStr, MentionPreviewsData, MentionPreviewsErrors, MentionPreviewsResponse, MentionPreviewsResponses, Mentions, Message, MessageAttachment, MessageChange, MessageCursor, MessageDirection, MessageEvent, MessageListItem, MessagePage, MessageParent, MessagePatch, MessageThread, MessageThreadPreview, MessageTimelineData, MessageTimelineQuery, MessageTimelineResponse, MessageTimelineResponses, NewAttachment, NewChannelAttachment, NewThreadAnchor, NotificationFilters, NotificationState, PairingDetails, Params, ParticipantRole, PatchBotRequest, PatchChannelData, PatchChannelError, PatchChannelErrors, PatchChannelRequest, PatchChannelResponse, PatchChannelResponses, PatchMessageData, PatchMessageError, PatchMessageErrors, PatchMessageNotificationPolicy, PatchMessageRequest, PatchMessageResponse, PatchMessageResponses, PatchProjectRequestV2, PatchThreadRequestV2, PatchViewHandlerData, PatchViewHandlerError, PatchViewHandlerErrors, PatchViewHandlerResponses, PatchWebhookData, PatchWebhookError, PatchWebhookErrors, PatchWebhookRequest, PatchWebhookResponse, PatchWebhookResponses, PdfAnchor, PdfAnchorId, PdfAnchorRequest, PdfHighlightAnchor, PdfHighlightAnchorRequest, PdfHighlightRect, PdfHighlightRectAnchorRequest, PdfPlaceableCommentAnchor, PdfPlaceableCommentAnchorRequest, PendingClaimResponse, PermanentlyDeleteDocumentData, PermanentlyDeleteDocumentError, PermanentlyDeleteDocumentErrors, PermanentlyDeleteDocumentResponse, PermanentlyDeleteDocumentResponses, PermanentlyDeleteProjectData, PermanentlyDeleteProjectError, PermanentlyDeleteProjectErrors, PermanentlyDeleteProjectResponse, PermanentlyDeleteProjectResponses, PinnedItem, PinRequest, PostActivityData, PostActivityError, PostActivityErrors, PostActivityRequest, PostActivityResponse, PostActivityResponses, PostChannelBotWebhookData, PostChannelBotWebhookError, PostChannelBotWebhookErrors, PostChannelBotWebhookResponse, PostChannelBotWebhookResponses, PostChannelMessagesData, PostChannelMessagesError, PostChannelMessagesErrors, PostChannelMessagesResponse, PostChannelMessagesResponses, PostGroupedSoupAstGroupPageRequest, PostGroupedSoupAstInitialRequest, PostGroupedSoupAstRequest, PostItemsSoupAstData, PostItemsSoupAstError, PostItemsSoupAstErrors, PostItemsSoupAstGroupedData, PostItemsSoupAstGroupedError, PostItemsSoupAstGroupedErrors, PostItemsSoupAstGroupedResponse, PostItemsSoupAstGroupedResponses, PostItemsSoupAstResponse, PostItemsSoupAstResponses, PostItemsSoupData, PostItemsSoupError, PostItemsSoupErrors, PostItemsSoupResponse, PostItemsSoupResponses, PostMessage, PostMessageData, PostMessageError, PostMessageErrors, PostMessageNotificationPolicy, PostMessageRequest, PostMessageResponse, PostMessageResponse2, PostMessageResponses, PostReactionData, PostReactionError, PostReactionErrors, PostReactionRequest, PostReactionResponse, PostReactionResponses, PostSoupAstRequest, PostSoupRequest, PostTypingData, PostTypingError, PostTypingErrors, PostTypingRequest, PostTypingResponse, PostTypingResponses, PresaveDocumentHandlerData, PresaveDocumentHandlerError, PresaveDocumentHandlerErrors, PresaveDocumentHandlerResponse, PresaveDocumentHandlerResponses, PreSaveDocumentRequest, PreSaveDocumentResponse, PreSaveDocumentResponseData, PresignedUrl, Project, ProjectDeleteResponseData, ProjectDocumentStatus, ProjectFilters, ProjectPreview, ProjectPreviewData, PropertyDefinition, PropertyFilter, PropertyInput, PropertyOwner, PropertyValue, PutCrmTeamSettingsData, PutCrmTeamSettingsError, PutCrmTeamSettingsErrors, PutCrmTeamSettingsResponse, PutCrmTeamSettingsResponses, PutCrmTeamStagesData, PutCrmTeamStagesError, PutCrmTeamStagesErrors, PutCrmTeamStagesResponse, PutCrmTeamStagesResponses, ReactionAction, ReactionInput, RecentlyDeletedData, RecentlyDeletedError, RecentlyDeletedErrors, RecentlyDeletedResponse, RecentlyDeletedResponseData, RecentlyDeletedResponses, ReferencedThread, ReferencedThreadPage, Reminder, ReminderFilters, ReminderSchedule, RemindersList, RemoveBotFromChannelByBotData, RemoveBotFromChannelByBotError, RemoveBotFromChannelByBotErrors, RemoveBotFromChannelByBotResponse, RemoveBotFromChannelByBotResponses, RemoveFavoriteByEntityData, RemoveFavoriteByEntityError, RemoveFavoriteByEntityErrors, RemoveFavoriteByEntityResponses, RemoveParticipantsData, RemoveParticipantsError, RemoveParticipantsErrors, RemoveParticipantsRequest, RemoveParticipantsResponses, RemovePinHandlerData, RemovePinHandlerError, RemovePinHandlerErrors, RemovePinHandlerResponse, RemovePinHandlerResponses, ReorderFavoritesData, ReorderFavoritesError, ReorderFavoritesErrors, ReorderFavoritesRequest, ReorderFavoritesResponses, ReorderPinRequest, ReorderPinsHandlerData, ReorderPinsHandlerError, ReorderPinsHandlerErrors, ReorderPinsHandlerResponse, ReorderPinsHandlerResponses, ReplaceCrmStagesRequest, RequestedHarnessScope, ResetCrmTeamStagesData, ResetCrmTeamStagesError, ResetCrmTeamStagesErrors, ResetCrmTeamStagesResponse, ResetCrmTeamStagesResponses, ResolveChannelMessageData, ResolveChannelMessageError, ResolveChannelMessageErrors, ResolveChannelMessageResponse, ResolveChannelMessageResponses, RevertDeleteDocumentData, RevertDeleteDocumentError, RevertDeleteDocumentErrors, RevertDeleteDocumentResponse, RevertDeleteDocumentResponses, RevertDeleteProjectData, RevertDeleteProjectError, RevertDeleteProjectErrors, RevertDeleteProjectResponse, RevertDeleteProjectResponses, RingStatus, RingStatusResponse, S3ObjectInfo, SaveBomPart, SaveDocumentHandlerData, SaveDocumentHandlerError, SaveDocumentHandlerErrors, SaveDocumentHandlerResponse, SaveDocumentHandlerResponses, SaveDocumentRequest, SaveDocumentResponse, SaveDocumentResponseData, SessionDeletedMetadata, SessionIdentity, SessionMentionedMetadata, SessionOpenedMetadata, SessionRenamedMetadata, SessionSettledMetadata, SessionStoppedMetadata, SetChannelPictureData, SetChannelPictureError, SetChannelPictureErrors, SetChannelPictureRequest, SetChannelPictureResponse, SetChannelPictureResponses, SetCompanyHiddenData, SetCompanyHiddenError, SetCompanyHiddenErrors, SetCompanyHiddenRequest, SetCompanyHiddenResponse, SetCompanyHiddenResponses, SetCompanyNameRequest, SetContactHiddenData, SetContactHiddenError, SetContactHiddenErrors, SetContactHiddenRequest, SetContactHiddenResponse, SetContactHiddenResponses, SetContactNameRequest, SetCrmCompanyNameData, SetCrmCompanyNameError, SetCrmCompanyNameErrors, SetCrmCompanyNameResponse, SetCrmCompanyNameResponses, SetCrmContactNameData, SetCrmContactNameError, SetCrmContactNameErrors, SetCrmContactNameResponse, SetCrmContactNameResponses, SetDocumentTeamShareData, SetDocumentTeamShareError, SetDocumentTeamShareErrors, SetDocumentTeamShareRequest, SetDocumentTeamShareResponse, SetDocumentTeamShareResponses, SetEmailSyncData, SetEmailSyncError, SetEmailSyncErrors, SetEmailSyncRequest, SetEmailSyncResponse, SetEmailSyncResponses, SetPropertyValue, SharedEmailFilter, SharePermissionV2, ShortIdResponse, SimpleMention, SimpleSaveData, SimpleSaveError, SimpleSaveErrors, SimpleSaveResponse, SimpleSaveResponses, SoupAgentSessionSoupPropertiesField, SoupApiItem, SoupApiSort, SoupApiSortDirection, SoupAttachment, SoupCalendarEventSoupPropertiesField, SoupCalendarEventTime, SoupCallRecordParticipant, SoupCallRecordSoupPropertiesField, SoupChannel, SoupChannelThread, SoupChatSoupPropertiesField, SoupContact, SoupCountedReaction, SoupCrmCompanySoupPropertiesField, SoupCrmDomain, SoupDocumentSoupPropertiesField, SoupDocumentSubType, SoupEmailThreadPreview, SoupEnrichedEmailThreadPreviewSoupPropertiesField, SoupForeignEntity, SoupItem, SoupLabel, SoupLabelListVisibility, SoupLabelType, SoupMessageAttachment, SoupMessageListVisibility, SoupMessageSender, SoupMessageSenderType, SoupPage, SoupProjectSoupPropertiesField, SoupPropertiesField, SoupProperty, SoupReminderReference, SoupReminderSchedule, SoupReminderSoupPropertiesField, SoupThreadInfo, SoupThreadReply, StarterDocumentsResponse, StreamEventsData, StreamEventsError, StreamEventsErrors, StreamEventsResponse, StreamEventsResponses, String, SuccessResponse, SurfaceState, SyncServiceVersionId, SystemSkillSummary, TagFilterMode, TaskFilters, TeamOutOfOfficeItem, TeamOutOfOfficeResponse, TeamRole, Thread, ThreadAnchor, ThreadOrigin, ThreadPatch, ThreadResponse, ThreadState, ToggleShareWithTeamData, ToggleShareWithTeamError, ToggleShareWithTeamErrors, ToggleShareWithTeamResponse, ToggleShareWithTeamResponses, TranscribeDictationData, TranscribeDictationError, TranscribeDictationErrors, TranscribeDictationResponse, TranscribeDictationResponses, TranscribeResponse, TranscriptSegmentRequest, TurnEndedMetadata, TurnStartedMetadata, TurnSummary, TypedSuccessResponse, TypedSuccessResponseGetDocumentResponseData, TypingAction, TypingInput, UnassignInitiativeTaskData, UnassignInitiativeTaskError, UnassignInitiativeTaskErrors, UnassignInitiativeTaskResponse, UnassignInitiativeTaskResponses, UnthreadedPdfUuidRequest, UpdateAgentData, UpdateAgentError, UpdateAgentErrors, UpdateAgentRequest, UpdateAgentResponse, UpdateAgentResponses, UpdateChannelSharePermission, UpdateCrmTeamSettingsRequest, UpdateInitiativeData, UpdateInitiativeError, UpdateInitiativeErrors, UpdateInitiativeRequest, UpdateInitiativeResponse, UpdateInitiativeResponses, UpdateOperation, UpdateReminderData, UpdateReminderError, UpdateReminderErrors, UpdateReminderRequest, UpdateReminderResponse, UpdateReminderResponses, UpdateSharePermissionRequestV2, UploadDocumentStatus, UploadExtractFolderHandlerData, UploadExtractFolderHandlerError, UploadExtractFolderHandlerErrors, UploadExtractFolderHandlerResponse, UploadExtractFolderHandlerResponses, UploadExtractFolderRequest, UploadFolderHandlerData, UploadFolderHandlerError, UploadFolderHandlerErrors, UploadFolderHandlerResponse, UploadFolderHandlerResponses, UploadFolderRequest, UpsertHistoryHandlerData, UpsertHistoryHandlerError, UpsertHistoryHandlerErrors, UpsertHistoryHandlerResponse, UpsertHistoryHandlerResponses, UpsertUserDocumentViewLocationData, UpsertUserDocumentViewLocationError, UpsertUserDocumentViewLocationErrors, UpsertUserDocumentViewLocationRequest, UpsertUserDocumentViewLocationResponse, UpsertUserDocumentViewLocationResponses, UserApiKeyId, UserApiKeyInfo, UserApiKeysList, UserDocumentsResponse, UserDocumentViewLocation, UserDocumentViewLocationResponse, UserPinsResponse, UserViewsResponse, ValidateDocumentPermissionsTokenData, ValidateDocumentPermissionsTokenError, ValidateDocumentPermissionsTokenErrors, ValidateDocumentPermissionsTokenResponse, ValidateDocumentPermissionsTokenResponses, ValidateWebhookData, ValidateWebhookError, ValidateWebhookErrors, ValidateWebhookResponse, ValidateWebhookResponse2, ValidateWebhookResponses, Vec, View, ViewPatch, ViewsResponse, WaitingForInputMetadata, Webhook, WebhookEvent, WebhookFilter, WebhookScope, WebhookStatus, WebhookValidationTestEvent, WithCallId, WithChannelId, WithDocumentId, WithProjectId } from './types.gen';
diff --git a/packages/sdk/generated/storage/sdk.gen.ts b/packages/sdk/generated/storage/sdk.gen.ts
index 183a9a840a2..630fd412c71 100644
--- a/packages/sdk/generated/storage/sdk.gen.ts
+++ b/packages/sdk/generated/storage/sdk.gen.ts
@@ -2,7 +2,7 @@
import type { Client, ClientMeta, Options as Options2, RequestResult, ServerSentEventsResult, TDataShape } from './client';
import { client } from './client.gen';
-import type { AddFavoriteData, AddFavoriteErrors, AddFavoriteResponses, AddParticipantsData, AddParticipantsErrors, AddParticipantsResponses, AddPinHandlerData, AddPinHandlerErrors, AddPinHandlerResponses, ApproveHarnessPairingData, ApproveHarnessPairingErrors, ApproveHarnessPairingResponses, AssignInitiativeTasksData, AssignInitiativeTasksErrors, AssignInitiativeTasksResponses, BulkWakeupSyncServiceDocumentsData, BulkWakeupSyncServiceDocumentsErrors, BulkWakeupSyncServiceDocumentsResponses, CallWebhookData, CallWebhookErrors, CallWebhookResponses, CheckActiveCallData, CheckActiveCallErrors, CheckActiveCallResponses, ClaimHarnessPairingData, ClaimHarnessPairingErrors, ClaimHarnessPairingResponses, CopyDocumentData, CopyDocumentErrors, CopyDocumentResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAnchorData, CreateAnchorErrors, CreateAnchorResponses, CreateChannelData, CreateChannelErrors, CreateChannelResponses, CreateChannelScopedBotData, CreateChannelScopedBotErrors, CreateChannelScopedBotResponses, CreateCollabSurfaceTokenData, CreateCollabSurfaceTokenErrors, CreateCollabSurfaceTokenResponses, CreateCommentData, CreateCommentErrors, CreateCommentResponses, CreateCrmCommentData, CreateCrmCommentErrors, CreateCrmCommentResponses, CreateCrmCompanyData, CreateCrmCompanyErrors, CreateCrmCompanyResponses, CreateCrmContactData, CreateCrmContactErrors, CreateCrmContactResponses, CreateDocumentData, CreateDocumentErrors, CreateDocumentResponses, CreateEntityMentionData, CreateEntityMentionErrors, CreateEntityMentionResponses, CreateHarnessPairingData, CreateHarnessPairingErrors, CreateHarnessPairingResponses, CreateInitiativeData, CreateInitiativeErrors, CreateInitiativeResponses, CreateInstructionsHandlerData, CreateInstructionsHandlerErrors, CreateInstructionsHandlerResponses, CreateMarkdownHandlerData, CreateMarkdownHandlerErrors, CreateMarkdownHandlerResponses, CreateProjectHandlerData, CreateProjectHandlerErrors, CreateProjectHandlerResponses, CreateReminderData, CreateReminderErrors, CreateReminderResponses, CreateSkillHandlerData, CreateSkillHandlerErrors, CreateSkillHandlerResponses, CreateSnippetHandlerData, CreateSnippetHandlerErrors, CreateSnippetHandlerResponses, CreateTaskHandlerData, CreateTaskHandlerErrors, CreateTaskHandlerResponses, CreateUserApiKeyData, CreateUserApiKeyErrors, CreateUserApiKeyResponses, CreateViewHandlerData, CreateViewHandlerErrors, CreateViewHandlerResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookResponses, DeleteAnchorData, DeleteAnchorErrors, DeleteAnchorResponses, DeleteCallRecordData, DeleteCallRecordErrors, DeleteCallRecordResponses, DeleteChannelData, DeleteChannelErrors, DeleteChannelResponses, DeleteCollabSurfaceData, DeleteCollabSurfaceErrors, DeleteCollabSurfaceResponses, DeleteCommentData, DeleteCommentErrors, DeleteCommentResponses, DeleteCrmCommentData, DeleteCrmCommentErrors, DeleteCrmCommentResponses, DeleteDocumentData, DeleteDocumentErrors, DeleteDocumentResponses, DeleteEntityMentionData, DeleteEntityMentionErrors, DeleteEntityMentionResponses, DeleteHarnessData, DeleteHarnessErrors, DeleteHarnessResponses, DeleteHistoryHandlerData, DeleteHistoryHandlerErrors, DeleteHistoryHandlerResponses, DeleteInitiativeData, DeleteInitiativeErrors, DeleteInitiativeResponses, DeleteMessageData, DeleteMessageErrors, DeleteMessageResponses, DeleteProjectHandlerData, DeleteProjectHandlerErrors, DeleteProjectHandlerResponses, DeleteReminderData, DeleteReminderErrors, DeleteReminderResponses, DeleteSelfHarnessData, DeleteSelfHarnessErrors, DeleteSelfHarnessResponses, DeleteUserApiKeyData, DeleteUserApiKeyErrors, DeleteUserApiKeyResponses, DeleteUserDocumentViewLocationData, DeleteUserDocumentViewLocationErrors, DeleteUserDocumentViewLocationResponses, DeleteViewHandlerData, DeleteViewHandlerErrors, DeleteViewHandlerResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, EditAnchorData, EditAnchorErrors, EditAnchorResponses, EditCallRecordData, EditCallRecordErrors, EditCallRecordResponses, EditCallTranscriptData, EditCallTranscriptErrors, EditCallTranscriptResponses, EditCommentData, EditCommentErrors, EditCommentResponses, EditCrmCommentData, EditCrmCommentErrors, EditCrmCommentResponses, EditDocumentData, EditDocumentErrors, EditDocumentResponses, EditProjectV2Data, EditProjectV2Errors, EditProjectV2Responses, EditThreadV2Data, EditThreadV2Errors, EditThreadV2Responses, EnsureCollabSurfaceData, EnsureCollabSurfaceErrors, EnsureCollabSurfaceResponses, EntityMessageCreateData, EntityMessageCreateResponses, EntityMessageDeleteMessageData, EntityMessageDeleteMessageResponses, EntityMessageDeleteThreadData, EntityMessageDeleteThreadResponses, EntityMessageEditData, EntityMessageEditResponses, EntityMessageGetMessageData, EntityMessageGetMessageResponses, EntityMessageGetThreadData, EntityMessageGetThreadResponses, EntityMessageLegacyData, EntityMessageLegacyResponses, EntityMessagePatchThreadData, EntityMessagePatchThreadResponses, EntityMessageReactData, EntityMessageReactResponses, EntityMessageReferencesData, EntityMessageReferencesResponses, EntityMessageTypingData, EntityMessageTypingResponses, ExcludeDefaultViewHandlerData, ExcludeDefaultViewHandlerErrors, ExcludeDefaultViewHandlerResponses, ExportDocumentData, ExportDocumentErrors, ExportDocumentResponses, GetActiveCallsData, GetActiveCallsErrors, GetActiveCallsResponses, GetActivityData, GetActivityErrors, GetActivityResponses, GetAttachmentReferencesData, GetAttachmentReferencesErrors, GetAttachmentReferencesResponses, GetBatchCallRecordPreviewData, GetBatchCallRecordPreviewErrors, GetBatchCallRecordPreviewResponses, GetBatchChannelPreviewData, GetBatchChannelPreviewErrors, GetBatchChannelPreviewResponses, GetBatchPreviewHandlerData, GetBatchPreviewHandlerErrors, GetBatchPreviewHandlerResponses, GetBatchProjectPreviewData, GetBatchProjectPreviewErrors, GetBatchProjectPreviewResponses, GetCallRecordData, GetCallRecordErrors, GetCallRecordResponses, GetChannelAttachmentsData, GetChannelAttachmentsErrors, GetChannelAttachmentsResponses, GetChannelData, GetChannelErrors, GetChannelJoinLinkData, GetChannelJoinLinkErrors, GetChannelJoinLinkResponses, GetChannelMessagesCatchUpData, GetChannelMessagesCatchUpErrors, GetChannelMessagesCatchUpResponses, GetChannelMessagesData, GetChannelMessagesErrors, GetChannelMessagesResponses, GetChannelParticipantsData, GetChannelParticipantsErrors, GetChannelParticipantsResponses, GetChannelResponses, GetChannelsData, GetChannelsErrors, GetChannelsResponses, GetCollabSurfaceData, GetCollabSurfaceErrors, GetCollabSurfaceResponses, GetCompanyData, GetCompanyErrors, GetCompanyResponses, GetContactByEmailData, GetContactByEmailErrors, GetContactByEmailResponses, GetContactData, GetContactErrors, GetContactResponses, GetCrmTeamSettingsData, GetCrmTeamSettingsErrors, GetCrmTeamSettingsResponses, GetDocumentAnchorsData, GetDocumentAnchorsErrors, GetDocumentAnchorsResponses, GetDocumentBranchNameData, GetDocumentBranchNameErrors, GetDocumentBranchNameResponses, GetDocumentByTeamSlugData, GetDocumentByTeamSlugErrors, GetDocumentByTeamSlugResponses, GetDocumentCommentsData, GetDocumentCommentsErrors, GetDocumentCommentsResponses, GetDocumentData, GetDocumentErrors, GetDocumentGithubPullRequestsData, GetDocumentGithubPullRequestsErrors, GetDocumentGithubPullRequestsResponses, GetDocumentListHandlerData, GetDocumentListHandlerErrors, GetDocumentListHandlerResponses, GetDocumentLocationV3Data, GetDocumentLocationV3Errors, GetDocumentLocationV3Responses, GetDocumentPermissionsTokenData, GetDocumentPermissionsTokenErrors, GetDocumentPermissionsTokenResponses, GetDocumentPermissionsV2Data, GetDocumentPermissionsV2Errors, GetDocumentPermissionsV2Responses, GetDocumentProcessingResultData, GetDocumentProcessingResultErrors, GetDocumentProcessingResultResponses, GetDocumentResponses, GetDocumentShortIdData, GetDocumentShortIdErrors, GetDocumentShortIdResponses, GetDocumentTeamShareData, GetDocumentTeamShareErrors, GetDocumentTeamShareResponses, GetDocumentVersionData, GetDocumentVersionErrors, GetDocumentVersionResponses, GetDocumentViewsHandlerData, GetDocumentViewsHandlerErrors, GetDocumentViewsHandlerResponses, GetEntityPermissionData, GetEntityPermissionErrors, GetEntityPermissionResponses, GetForeignEntityBySourceData, GetForeignEntityBySourceErrors, GetForeignEntityBySourceResponses, GetForeignEntityData, GetForeignEntityErrors, GetForeignEntityResponses, GetHarnessPairingData, GetHarnessPairingErrors, GetHarnessPairingResponses, GetHistoryHandlerData, GetHistoryHandlerErrors, GetHistoryHandlerResponses, GetInitiativeData, GetInitiativeErrors, GetInitiativeResponses, GetInstructionsHandlerData, GetInstructionsHandlerErrors, GetInstructionsHandlerResponses, GetItemsSoupData, GetItemsSoupErrors, GetItemsSoupResponses, GetLocationHandlerData, GetLocationHandlerErrors, GetLocationHandlerResponses, GetMessageWithContextData, GetMessageWithContextErrors, GetMessageWithContextResponses, GetOrCreateCallData, GetOrCreateCallErrors, GetOrCreateCallResponses, GetOrCreateDmData, GetOrCreateDmErrors, GetOrCreateDmResponses, GetOrCreatePrivateData, GetOrCreatePrivateErrors, GetOrCreatePrivateResponses, GetPendingProjectsHandlerData, GetPendingProjectsHandlerErrors, GetPendingProjectsHandlerResponses, GetPinsHandlerData, GetPinsHandlerErrors, GetPinsHandlerResponses, GetProjectContentHandlerData, GetProjectContentHandlerErrors, GetProjectContentHandlerResponses, GetProjectHandlerData, GetProjectHandlerErrors, GetProjectHandlerResponses, GetProjectPermissionsV2Data, GetProjectPermissionsV2Errors, GetProjectPermissionsV2Responses, GetProjectsHandlerData, GetProjectsHandlerErrors, GetProjectsHandlerResponses, GetProjectUserAccessLevelData, GetProjectUserAccessLevelErrors, GetProjectUserAccessLevelResponses, GetReminderData, GetReminderErrors, GetReminderResponses, GetRingStatusData, GetRingStatusErrors, GetRingStatusResponses, GetSelfBotData, GetSelfBotErrors, GetSelfBotResponses, GetSelfHarnessData, GetSelfHarnessErrors, GetSelfHarnessResponses, GetSystemSkillsHandlerData, GetSystemSkillsHandlerErrors, GetSystemSkillsHandlerResponses, GetThreadRepliesData, GetThreadRepliesErrors, GetThreadRepliesResponses, GetUserDocumentsHandlerData, GetUserDocumentsHandlerErrors, GetUserDocumentsHandlerResponses, GetUserDocumentViewLocationData, GetUserDocumentViewLocationErrors, GetUserDocumentViewLocationResponses, GetViewsHandlerData, GetViewsHandlerErrors, GetViewsHandlerResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, HandlerData, HandlerErrors, HandlerResponses, HealthHandlerData, HealthHandlerResponses, IngestTranscriptData, IngestTranscriptErrors, IngestTranscriptResponses, InitializeUserDocumentsData, InitializeUserDocumentsErrors, InitializeUserDocumentsResponses, InstallSyncData, InstallSyncErrors, JobProcessingResultHandlerData, JobProcessingResultHandlerErrors, JobProcessingResultHandlerResponses, JoinChannelByCodeData, JoinChannelByCodeErrors, JoinChannelByCodeResponses, JoinChannelData, JoinChannelErrors, JoinChannelResponses, LeaveChannelData, LeaveChannelErrors, LeaveChannelResponses, LeaveOrEndCallData, LeaveOrEndCallErrors, LeaveOrEndCallResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListBotChannelsData, ListBotChannelsErrors, ListBotChannelsResponses, ListCompanyContactsData, ListCompanyContactsErrors, ListCompanyContactsResponses, ListCrmCommentsData, ListCrmCommentsErrors, ListCrmCommentsResponses, ListFavoritesData, ListFavoritesErrors, ListFavoritesResponses, ListHarnessAgentsData, ListHarnessAgentsErrors, ListHarnessAgentsResponses, ListHarnessesData, ListHarnessesErrors, ListHarnessesResponses, ListHarnessSessionsData, ListHarnessSessionsErrors, ListHarnessSessionsResponses, ListInitiativesData, ListInitiativesErrors, ListInitiativesResponses, ListOccurrencesData, ListOccurrencesErrors, ListOccurrencesResponses, ListRemindersData, ListRemindersErrors, ListRemindersResponses, ListTeamOutOfOfficeData, ListTeamOutOfOfficeErrors, ListTeamOutOfOfficeResponses, ListUserApiKeysData, ListUserApiKeysErrors, ListUserApiKeysResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, MentionPreviewsData, MentionPreviewsErrors, MentionPreviewsResponses, MessageTimelineData, MessageTimelineResponses, PatchChannelData, PatchChannelErrors, PatchChannelResponses, PatchMessageData, PatchMessageErrors, PatchMessageResponses, PatchViewHandlerData, PatchViewHandlerErrors, PatchViewHandlerResponses, PatchWebhookData, PatchWebhookErrors, PatchWebhookResponses, PermanentlyDeleteDocumentData, PermanentlyDeleteDocumentErrors, PermanentlyDeleteDocumentResponses, PermanentlyDeleteProjectData, PermanentlyDeleteProjectErrors, PermanentlyDeleteProjectResponses, PostActivityData, PostActivityErrors, PostActivityResponses, PostChannelBotWebhookData, PostChannelBotWebhookErrors, PostChannelBotWebhookResponses, PostChannelMessagesData, PostChannelMessagesErrors, PostChannelMessagesResponses, PostItemsSoupAstData, PostItemsSoupAstErrors, PostItemsSoupAstGroupedData, PostItemsSoupAstGroupedErrors, PostItemsSoupAstGroupedResponses, PostItemsSoupAstResponses, PostItemsSoupData, PostItemsSoupErrors, PostItemsSoupResponses, PostMessageData, PostMessageErrors, PostMessageResponses, PostReactionData, PostReactionErrors, PostReactionResponses, PostTypingData, PostTypingErrors, PostTypingResponses, PresaveDocumentHandlerData, PresaveDocumentHandlerErrors, PresaveDocumentHandlerResponses, PutCrmTeamSettingsData, PutCrmTeamSettingsErrors, PutCrmTeamSettingsResponses, PutCrmTeamStagesData, PutCrmTeamStagesErrors, PutCrmTeamStagesResponses, RecentlyDeletedData, RecentlyDeletedErrors, RecentlyDeletedResponses, RemoveBotFromChannelByBotData, RemoveBotFromChannelByBotErrors, RemoveBotFromChannelByBotResponses, RemoveFavoriteByEntityData, RemoveFavoriteByEntityErrors, RemoveFavoriteByEntityResponses, RemoveParticipantsData, RemoveParticipantsErrors, RemoveParticipantsResponses, RemovePinHandlerData, RemovePinHandlerErrors, RemovePinHandlerResponses, ReorderFavoritesData, ReorderFavoritesErrors, ReorderFavoritesResponses, ReorderPinsHandlerData, ReorderPinsHandlerErrors, ReorderPinsHandlerResponses, ResetCrmTeamStagesData, ResetCrmTeamStagesErrors, ResetCrmTeamStagesResponses, ResolveChannelMessageData, ResolveChannelMessageErrors, ResolveChannelMessageResponses, RevertDeleteDocumentData, RevertDeleteDocumentErrors, RevertDeleteDocumentResponses, RevertDeleteProjectData, RevertDeleteProjectErrors, RevertDeleteProjectResponses, SaveDocumentHandlerData, SaveDocumentHandlerErrors, SaveDocumentHandlerResponses, SetChannelPictureData, SetChannelPictureErrors, SetChannelPictureResponses, SetCompanyHiddenData, SetCompanyHiddenErrors, SetCompanyHiddenResponses, SetContactHiddenData, SetContactHiddenErrors, SetContactHiddenResponses, SetCrmCompanyNameData, SetCrmCompanyNameErrors, SetCrmCompanyNameResponses, SetCrmContactNameData, SetCrmContactNameErrors, SetCrmContactNameResponses, SetDocumentTeamShareData, SetDocumentTeamShareErrors, SetDocumentTeamShareResponses, SetEmailSyncData, SetEmailSyncErrors, SetEmailSyncResponses, SimpleSaveData, SimpleSaveErrors, SimpleSaveResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponse, StreamEventsResponses, ToggleShareWithTeamData, ToggleShareWithTeamErrors, ToggleShareWithTeamResponses, UnassignInitiativeTaskData, UnassignInitiativeTaskErrors, UnassignInitiativeTaskResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateInitiativeData, UpdateInitiativeErrors, UpdateInitiativeResponses, UpdateReminderData, UpdateReminderErrors, UpdateReminderResponses, UploadExtractFolderHandlerData, UploadExtractFolderHandlerErrors, UploadExtractFolderHandlerResponses, UploadFolderHandlerData, UploadFolderHandlerErrors, UploadFolderHandlerResponses, UpsertHistoryHandlerData, UpsertHistoryHandlerErrors, UpsertHistoryHandlerResponses, UpsertUserDocumentViewLocationData, UpsertUserDocumentViewLocationErrors, UpsertUserDocumentViewLocationResponses, ValidateDocumentPermissionsTokenData, ValidateDocumentPermissionsTokenErrors, ValidateDocumentPermissionsTokenResponses, ValidateWebhookData, ValidateWebhookErrors, ValidateWebhookResponses } from './types.gen';
+import type { AddFavoriteData, AddFavoriteErrors, AddFavoriteResponses, AddParticipantsData, AddParticipantsErrors, AddParticipantsResponses, AddPinHandlerData, AddPinHandlerErrors, AddPinHandlerResponses, ApproveHarnessPairingData, ApproveHarnessPairingErrors, ApproveHarnessPairingResponses, AssignInitiativeTasksData, AssignInitiativeTasksErrors, AssignInitiativeTasksResponses, BulkWakeupSyncServiceDocumentsData, BulkWakeupSyncServiceDocumentsErrors, BulkWakeupSyncServiceDocumentsResponses, CallWebhookData, CallWebhookErrors, CallWebhookResponses, CheckActiveCallData, CheckActiveCallErrors, CheckActiveCallResponses, ClaimHarnessPairingData, ClaimHarnessPairingErrors, ClaimHarnessPairingResponses, CopyDocumentData, CopyDocumentErrors, CopyDocumentResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAnchorData, CreateAnchorErrors, CreateAnchorResponses, CreateChannelData, CreateChannelErrors, CreateChannelResponses, CreateChannelScopedBotData, CreateChannelScopedBotErrors, CreateChannelScopedBotResponses, CreateCollabSurfaceTokenData, CreateCollabSurfaceTokenErrors, CreateCollabSurfaceTokenResponses, CreateCommentData, CreateCommentErrors, CreateCommentResponses, CreateCrmCommentData, CreateCrmCommentErrors, CreateCrmCommentResponses, CreateCrmCompanyData, CreateCrmCompanyErrors, CreateCrmCompanyResponses, CreateCrmContactData, CreateCrmContactErrors, CreateCrmContactResponses, CreateDocumentData, CreateDocumentErrors, CreateDocumentResponses, CreateEntityMentionData, CreateEntityMentionErrors, CreateEntityMentionResponses, CreateHarnessPairingData, CreateHarnessPairingErrors, CreateHarnessPairingResponses, CreateInitiativeData, CreateInitiativeErrors, CreateInitiativeResponses, CreateInstructionsHandlerData, CreateInstructionsHandlerErrors, CreateInstructionsHandlerResponses, CreateMarkdownHandlerData, CreateMarkdownHandlerErrors, CreateMarkdownHandlerResponses, CreateProjectHandlerData, CreateProjectHandlerErrors, CreateProjectHandlerResponses, CreateReminderData, CreateReminderErrors, CreateReminderResponses, CreateSkillHandlerData, CreateSkillHandlerErrors, CreateSkillHandlerResponses, CreateSnippetHandlerData, CreateSnippetHandlerErrors, CreateSnippetHandlerResponses, CreateTaskHandlerData, CreateTaskHandlerErrors, CreateTaskHandlerResponses, CreateUserApiKeyData, CreateUserApiKeyErrors, CreateUserApiKeyResponses, CreateViewHandlerData, CreateViewHandlerErrors, CreateViewHandlerResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookResponses, DeleteAnchorData, DeleteAnchorErrors, DeleteAnchorResponses, DeleteCallRecordData, DeleteCallRecordErrors, DeleteCallRecordResponses, DeleteChannelData, DeleteChannelErrors, DeleteChannelResponses, DeleteCollabSurfaceData, DeleteCollabSurfaceErrors, DeleteCollabSurfaceResponses, DeleteCommentData, DeleteCommentErrors, DeleteCommentResponses, DeleteCrmCommentData, DeleteCrmCommentErrors, DeleteCrmCommentResponses, DeleteDocumentData, DeleteDocumentErrors, DeleteDocumentResponses, DeleteEntityMentionData, DeleteEntityMentionErrors, DeleteEntityMentionResponses, DeleteHarnessData, DeleteHarnessErrors, DeleteHarnessResponses, DeleteHistoryHandlerData, DeleteHistoryHandlerErrors, DeleteHistoryHandlerResponses, DeleteInitiativeData, DeleteInitiativeErrors, DeleteInitiativeResponses, DeleteMessageData, DeleteMessageErrors, DeleteMessageResponses, DeleteProjectHandlerData, DeleteProjectHandlerErrors, DeleteProjectHandlerResponses, DeleteReminderData, DeleteReminderErrors, DeleteReminderResponses, DeleteSelfHarnessData, DeleteSelfHarnessErrors, DeleteSelfHarnessResponses, DeleteUserApiKeyData, DeleteUserApiKeyErrors, DeleteUserApiKeyResponses, DeleteUserDocumentViewLocationData, DeleteUserDocumentViewLocationErrors, DeleteUserDocumentViewLocationResponses, DeleteViewHandlerData, DeleteViewHandlerErrors, DeleteViewHandlerResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, EditAnchorData, EditAnchorErrors, EditAnchorResponses, EditCallRecordData, EditCallRecordErrors, EditCallRecordResponses, EditCallTranscriptData, EditCallTranscriptErrors, EditCallTranscriptResponses, EditCommentData, EditCommentErrors, EditCommentResponses, EditCrmCommentData, EditCrmCommentErrors, EditCrmCommentResponses, EditDocumentData, EditDocumentErrors, EditDocumentResponses, EditProjectV2Data, EditProjectV2Errors, EditProjectV2Responses, EditThreadV2Data, EditThreadV2Errors, EditThreadV2Responses, EnsureCollabSurfaceData, EnsureCollabSurfaceErrors, EnsureCollabSurfaceResponses, EntityMessageCreateData, EntityMessageCreateResponses, EntityMessageDeleteMessageData, EntityMessageDeleteMessageResponses, EntityMessageDeleteThreadData, EntityMessageDeleteThreadResponses, EntityMessageEditData, EntityMessageEditResponses, EntityMessageGetMessageData, EntityMessageGetMessageResponses, EntityMessageGetThreadData, EntityMessageGetThreadResponses, EntityMessageLegacyData, EntityMessageLegacyResponses, EntityMessagePatchThreadData, EntityMessagePatchThreadResponses, EntityMessageReactData, EntityMessageReactResponses, EntityMessageReferencesData, EntityMessageReferencesResponses, EntityMessageTypingData, EntityMessageTypingResponses, ExcludeDefaultViewHandlerData, ExcludeDefaultViewHandlerErrors, ExcludeDefaultViewHandlerResponses, ExportDocumentData, ExportDocumentErrors, ExportDocumentResponses, GetActiveCallsData, GetActiveCallsErrors, GetActiveCallsResponses, GetActivityData, GetActivityErrors, GetActivityResponses, GetAttachmentReferencesData, GetAttachmentReferencesErrors, GetAttachmentReferencesResponses, GetBatchCallRecordPreviewData, GetBatchCallRecordPreviewErrors, GetBatchCallRecordPreviewResponses, GetBatchChannelPreviewData, GetBatchChannelPreviewErrors, GetBatchChannelPreviewResponses, GetBatchPreviewHandlerData, GetBatchPreviewHandlerErrors, GetBatchPreviewHandlerResponses, GetBatchProjectPreviewData, GetBatchProjectPreviewErrors, GetBatchProjectPreviewResponses, GetCallRecordData, GetCallRecordErrors, GetCallRecordResponses, GetChannelAttachmentsData, GetChannelAttachmentsErrors, GetChannelAttachmentsResponses, GetChannelData, GetChannelErrors, GetChannelJoinLinkData, GetChannelJoinLinkErrors, GetChannelJoinLinkResponses, GetChannelMessagesCatchUpData, GetChannelMessagesCatchUpErrors, GetChannelMessagesCatchUpResponses, GetChannelMessagesData, GetChannelMessagesErrors, GetChannelMessagesResponses, GetChannelParticipantsData, GetChannelParticipantsErrors, GetChannelParticipantsResponses, GetChannelResponses, GetChannelsData, GetChannelsErrors, GetChannelsResponses, GetCollabSurfaceData, GetCollabSurfaceErrors, GetCollabSurfaceResponses, GetCompanyData, GetCompanyErrors, GetCompanyResponses, GetContactByEmailData, GetContactByEmailErrors, GetContactByEmailResponses, GetContactData, GetContactErrors, GetContactResponses, GetCrmTeamSettingsData, GetCrmTeamSettingsErrors, GetCrmTeamSettingsResponses, GetDocumentAnchorsData, GetDocumentAnchorsErrors, GetDocumentAnchorsResponses, GetDocumentBranchNameData, GetDocumentBranchNameErrors, GetDocumentBranchNameResponses, GetDocumentByTeamSlugData, GetDocumentByTeamSlugErrors, GetDocumentByTeamSlugResponses, GetDocumentCommentsData, GetDocumentCommentsErrors, GetDocumentCommentsResponses, GetDocumentData, GetDocumentErrors, GetDocumentGithubPullRequestsData, GetDocumentGithubPullRequestsErrors, GetDocumentGithubPullRequestsResponses, GetDocumentListHandlerData, GetDocumentListHandlerErrors, GetDocumentListHandlerResponses, GetDocumentLocationV3Data, GetDocumentLocationV3Errors, GetDocumentLocationV3Responses, GetDocumentPermissionsTokenData, GetDocumentPermissionsTokenErrors, GetDocumentPermissionsTokenResponses, GetDocumentPermissionsV2Data, GetDocumentPermissionsV2Errors, GetDocumentPermissionsV2Responses, GetDocumentProcessingResultData, GetDocumentProcessingResultErrors, GetDocumentProcessingResultResponses, GetDocumentResponses, GetDocumentShortIdData, GetDocumentShortIdErrors, GetDocumentShortIdResponses, GetDocumentTeamShareData, GetDocumentTeamShareErrors, GetDocumentTeamShareResponses, GetDocumentVersionData, GetDocumentVersionErrors, GetDocumentVersionResponses, GetDocumentViewsHandlerData, GetDocumentViewsHandlerErrors, GetDocumentViewsHandlerResponses, GetEntityPermissionData, GetEntityPermissionErrors, GetEntityPermissionResponses, GetForeignEntityBySourceData, GetForeignEntityBySourceErrors, GetForeignEntityBySourceResponses, GetForeignEntityData, GetForeignEntityErrors, GetForeignEntityResponses, GetHarnessPairingData, GetHarnessPairingErrors, GetHarnessPairingResponses, GetHistoryHandlerData, GetHistoryHandlerErrors, GetHistoryHandlerResponses, GetInitiativeData, GetInitiativeErrors, GetInitiativeResponses, GetInstructionsHandlerData, GetInstructionsHandlerErrors, GetInstructionsHandlerResponses, GetItemsSoupData, GetItemsSoupErrors, GetItemsSoupResponses, GetLocationHandlerData, GetLocationHandlerErrors, GetLocationHandlerResponses, GetMessageWithContextData, GetMessageWithContextErrors, GetMessageWithContextResponses, GetOrCreateCallData, GetOrCreateCallErrors, GetOrCreateCallResponses, GetOrCreateDmData, GetOrCreateDmErrors, GetOrCreateDmResponses, GetOrCreatePrivateData, GetOrCreatePrivateErrors, GetOrCreatePrivateResponses, GetPendingProjectsHandlerData, GetPendingProjectsHandlerErrors, GetPendingProjectsHandlerResponses, GetPinsHandlerData, GetPinsHandlerErrors, GetPinsHandlerResponses, GetProjectContentHandlerData, GetProjectContentHandlerErrors, GetProjectContentHandlerResponses, GetProjectHandlerData, GetProjectHandlerErrors, GetProjectHandlerResponses, GetProjectPermissionsV2Data, GetProjectPermissionsV2Errors, GetProjectPermissionsV2Responses, GetProjectsHandlerData, GetProjectsHandlerErrors, GetProjectsHandlerResponses, GetProjectUserAccessLevelData, GetProjectUserAccessLevelErrors, GetProjectUserAccessLevelResponses, GetReminderData, GetReminderErrors, GetReminderResponses, GetRingStatusData, GetRingStatusErrors, GetRingStatusResponses, GetSelfBotData, GetSelfBotErrors, GetSelfBotResponses, GetSelfHarnessData, GetSelfHarnessErrors, GetSelfHarnessResponses, GetSystemSkillsHandlerData, GetSystemSkillsHandlerErrors, GetSystemSkillsHandlerResponses, GetThreadRepliesData, GetThreadRepliesErrors, GetThreadRepliesResponses, GetUserDocumentsHandlerData, GetUserDocumentsHandlerErrors, GetUserDocumentsHandlerResponses, GetUserDocumentViewLocationData, GetUserDocumentViewLocationErrors, GetUserDocumentViewLocationResponses, GetViewsHandlerData, GetViewsHandlerErrors, GetViewsHandlerResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, HandlerData, HandlerErrors, HandlerResponses, HealthHandlerData, HealthHandlerResponses, IngestTranscriptData, IngestTranscriptErrors, IngestTranscriptResponses, InitializeUserDocumentsData, InitializeUserDocumentsErrors, InitializeUserDocumentsResponses, InstallSyncData, InstallSyncErrors, JobProcessingResultHandlerData, JobProcessingResultHandlerErrors, JobProcessingResultHandlerResponses, JoinChannelByCodeData, JoinChannelByCodeErrors, JoinChannelByCodeResponses, JoinChannelData, JoinChannelErrors, JoinChannelResponses, LeaveChannelData, LeaveChannelErrors, LeaveChannelResponses, LeaveOrEndCallData, LeaveOrEndCallErrors, LeaveOrEndCallResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListBotChannelsData, ListBotChannelsErrors, ListBotChannelsResponses, ListCompanyContactsData, ListCompanyContactsErrors, ListCompanyContactsResponses, ListCrmCommentsData, ListCrmCommentsErrors, ListCrmCommentsResponses, ListFavoritesData, ListFavoritesErrors, ListFavoritesResponses, ListHarnessAgentsData, ListHarnessAgentsErrors, ListHarnessAgentsResponses, ListHarnessesData, ListHarnessesErrors, ListHarnessesResponses, ListHarnessSessionsData, ListHarnessSessionsErrors, ListHarnessSessionsResponses, ListInitiativesData, ListInitiativesErrors, ListInitiativesResponses, ListOccurrencesData, ListOccurrencesErrors, ListOccurrencesResponses, ListRemindersData, ListRemindersErrors, ListRemindersResponses, ListTeamOutOfOfficeData, ListTeamOutOfOfficeErrors, ListTeamOutOfOfficeResponses, ListUserApiKeysData, ListUserApiKeysErrors, ListUserApiKeysResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, MentionPreviewsData, MentionPreviewsErrors, MentionPreviewsResponses, MessageTimelineData, MessageTimelineResponses, PatchChannelData, PatchChannelErrors, PatchChannelResponses, PatchMessageData, PatchMessageErrors, PatchMessageResponses, PatchViewHandlerData, PatchViewHandlerErrors, PatchViewHandlerResponses, PatchWebhookData, PatchWebhookErrors, PatchWebhookResponses, PermanentlyDeleteDocumentData, PermanentlyDeleteDocumentErrors, PermanentlyDeleteDocumentResponses, PermanentlyDeleteProjectData, PermanentlyDeleteProjectErrors, PermanentlyDeleteProjectResponses, PostActivityData, PostActivityErrors, PostActivityResponses, PostChannelBotWebhookData, PostChannelBotWebhookErrors, PostChannelBotWebhookResponses, PostChannelMessagesData, PostChannelMessagesErrors, PostChannelMessagesResponses, PostItemsSoupAstData, PostItemsSoupAstErrors, PostItemsSoupAstGroupedData, PostItemsSoupAstGroupedErrors, PostItemsSoupAstGroupedResponses, PostItemsSoupAstResponses, PostItemsSoupData, PostItemsSoupErrors, PostItemsSoupResponses, PostMessageData, PostMessageErrors, PostMessageResponses, PostReactionData, PostReactionErrors, PostReactionResponses, PostTypingData, PostTypingErrors, PostTypingResponses, PresaveDocumentHandlerData, PresaveDocumentHandlerErrors, PresaveDocumentHandlerResponses, PutCrmTeamSettingsData, PutCrmTeamSettingsErrors, PutCrmTeamSettingsResponses, PutCrmTeamStagesData, PutCrmTeamStagesErrors, PutCrmTeamStagesResponses, RecentlyDeletedData, RecentlyDeletedErrors, RecentlyDeletedResponses, RemoveBotFromChannelByBotData, RemoveBotFromChannelByBotErrors, RemoveBotFromChannelByBotResponses, RemoveFavoriteByEntityData, RemoveFavoriteByEntityErrors, RemoveFavoriteByEntityResponses, RemoveParticipantsData, RemoveParticipantsErrors, RemoveParticipantsResponses, RemovePinHandlerData, RemovePinHandlerErrors, RemovePinHandlerResponses, ReorderFavoritesData, ReorderFavoritesErrors, ReorderFavoritesResponses, ReorderPinsHandlerData, ReorderPinsHandlerErrors, ReorderPinsHandlerResponses, ResetCrmTeamStagesData, ResetCrmTeamStagesErrors, ResetCrmTeamStagesResponses, ResolveChannelMessageData, ResolveChannelMessageErrors, ResolveChannelMessageResponses, RevertDeleteDocumentData, RevertDeleteDocumentErrors, RevertDeleteDocumentResponses, RevertDeleteProjectData, RevertDeleteProjectErrors, RevertDeleteProjectResponses, SaveDocumentHandlerData, SaveDocumentHandlerErrors, SaveDocumentHandlerResponses, SetChannelPictureData, SetChannelPictureErrors, SetChannelPictureResponses, SetCompanyHiddenData, SetCompanyHiddenErrors, SetCompanyHiddenResponses, SetContactHiddenData, SetContactHiddenErrors, SetContactHiddenResponses, SetCrmCompanyNameData, SetCrmCompanyNameErrors, SetCrmCompanyNameResponses, SetCrmContactNameData, SetCrmContactNameErrors, SetCrmContactNameResponses, SetDocumentTeamShareData, SetDocumentTeamShareErrors, SetDocumentTeamShareResponses, SetEmailSyncData, SetEmailSyncErrors, SetEmailSyncResponses, SimpleSaveData, SimpleSaveErrors, SimpleSaveResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponse, StreamEventsResponses, ToggleShareWithTeamData, ToggleShareWithTeamErrors, ToggleShareWithTeamResponses, TranscribeDictationData, TranscribeDictationErrors, TranscribeDictationResponses, UnassignInitiativeTaskData, UnassignInitiativeTaskErrors, UnassignInitiativeTaskResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateInitiativeData, UpdateInitiativeErrors, UpdateInitiativeResponses, UpdateReminderData, UpdateReminderErrors, UpdateReminderResponses, UploadExtractFolderHandlerData, UploadExtractFolderHandlerErrors, UploadExtractFolderHandlerResponses, UploadFolderHandlerData, UploadFolderHandlerErrors, UploadFolderHandlerResponses, UpsertHistoryHandlerData, UpsertHistoryHandlerErrors, UpsertHistoryHandlerResponses, UpsertUserDocumentViewLocationData, UpsertUserDocumentViewLocationErrors, UpsertUserDocumentViewLocationResponses, ValidateDocumentPermissionsTokenData, ValidateDocumentPermissionsTokenErrors, ValidateDocumentPermissionsTokenResponses, ValidateWebhookData, ValidateWebhookErrors, ValidateWebhookResponses } from './types.gen';
export type Options = Options2 & {
/**
@@ -1085,6 +1085,24 @@ export class Sdk extends HeyApiClient {
});
}
+ /**
+ * Transcribe a transient recording with OpenAI Whisper.
+ *
+ * Available to every signed-in user on every plan; does not consume chat
+ * credits. Audio and transcripts are never persisted.
+ */
+ public transcribeDictation(options: Options): RequestResult {
+ return (options.client ?? this.client).post({
+ bodySerializer: null,
+ url: '/dictation/transcribe',
+ ...options,
+ headers: {
+ 'Content-Type': 'audio/webm',
+ ...options.headers
+ }
+ });
+ }
+
/**
* Gets the users documents to populate their recent document list
*/
diff --git a/packages/sdk/generated/storage/types.gen.ts b/packages/sdk/generated/storage/types.gen.ts
index c487d888fe6..93671d32a63 100644
--- a/packages/sdk/generated/storage/types.gen.ts
+++ b/packages/sdk/generated/storage/types.gen.ts
@@ -9921,6 +9921,16 @@ export type ThreadState = {
user_id: string;
};
+/**
+ * Transcription result.
+ */
+export type TranscribeResponse = {
+ /**
+ * Recognized text.
+ */
+ text: string;
+};
+
/**
* A transcript segment from LiveKit Inference STT.
*/
@@ -13128,6 +13138,64 @@ export type PutCrmTeamStagesResponses = {
export type PutCrmTeamStagesResponse = PutCrmTeamStagesResponses[keyof PutCrmTeamStagesResponses];
+export type TranscribeDictationData = {
+ /**
+ * OpenAPI representation of the raw encoded audio body extracted as `Bytes`.
+ */
+ body: Blob | File;
+ path?: never;
+ query?: {
+ /**
+ * ISO 639-1 language hint
+ */
+ language?: string;
+ };
+ url: '/dictation/transcribe';
+};
+
+export type TranscribeDictationErrors = {
+ /**
+ * Empty, oversized, or malformed request
+ */
+ 400: ErrorResponse;
+ /**
+ * Missing or invalid credentials
+ */
+ 401: ErrorResponse;
+ /**
+ * Only signed-in users may dictate
+ */
+ 403: ErrorResponse;
+ /**
+ * Body exceeds 8 MiB
+ */
+ 413: unknown;
+ /**
+ * Unsupported audio container
+ */
+ 415: ErrorResponse;
+ /**
+ * Per-user hourly rate limit exceeded
+ */
+ 429: unknown;
+ /**
+ * Provider failure
+ */
+ 502: ErrorResponse;
+ /**
+ * Transcription capacity exhausted; retry after the Retry-After delay
+ */
+ 503: ErrorResponse;
+};
+
+export type TranscribeDictationError = TranscribeDictationErrors[keyof TranscribeDictationErrors];
+
+export type TranscribeDictationResponses = {
+ 200: TranscribeResponse;
+};
+
+export type TranscribeDictationResponse = TranscribeDictationResponses[keyof TranscribeDictationResponses];
+
export type GetUserDocumentsHandlerData = {
body?: never;
path?: never;
diff --git a/packages/sdk/specs/cognition.json b/packages/sdk/specs/cognition.json
index 96393c74f1b..13f6531e342 100644
--- a/packages/sdk/specs/cognition.json
+++ b/packages/sdk/specs/cognition.json
@@ -30,6 +30,16 @@
"200": {
"description": "Pricing updated"
},
+ "400": {
+ "description": "Invalid pricing",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorBody"
+ }
+ }
+ }
+ },
"403": {
"description": "Admin access required",
"content": {
@@ -2132,7 +2142,8 @@
"ai_editing",
"import",
"agent_session",
- "agent_repository_choice"
+ "agent_repository_choice",
+ "dictation"
]
},
"AssistantMessagePart": {
@@ -2806,25 +2817,25 @@
},
"CompletionUsage": {
"type": "object",
- "description": "A recorded completion: who, what feature, optional entity, and the cost.",
+ "description": "User and feature attribution for one invocation.",
"required": ["feature", "user", "cost"],
"properties": {
"cost": {
"$ref": "#/components/schemas/Usage",
- "description": "Token usage and cost."
+ "description": "Measured usage and resolved cost."
},
"entity": {
"type": ["string", "null"],
"format": "uuid",
- "description": "The entity the completion related to, if any."
+ "description": "Related entity, if any."
},
"feature": {
"$ref": "#/components/schemas/AiFeature",
- "description": "The feature that performed the completion."
+ "description": "Feature that performed the invocation."
},
"user": {
"$ref": "#/components/schemas/MacroUserIdStr",
- "description": "The user the completion was performed for (the [system user](SYSTEM_USER_ID)\nfor background work)."
+ "description": "User the invocation was performed for."
}
}
},
@@ -3006,7 +3017,7 @@
},
"FeatureUsage": {
"type": "object",
- "description": "Usage for a single feature, with its rolled-up dollar total.",
+ "description": "Recorded invocations and total for one feature.",
"required": ["feature", "entries", "total"],
"properties": {
"entries": {
@@ -3014,16 +3025,16 @@
"items": {
"$ref": "#/components/schemas/CompletionUsage"
},
- "description": "The individual completions recorded for this feature."
+ "description": "Recorded invocations."
},
"feature": {
"$ref": "#/components/schemas/AiFeature",
- "description": "The feature."
+ "description": "Feature attribution."
},
"total": {
"type": "number",
"format": "float",
- "description": "Total cost across `entries` (USD)."
+ "description": "Total cost (USD)."
}
}
},
@@ -4087,23 +4098,28 @@
},
"Price": {
"type": "object",
- "description": "Resolved price for one completion.",
+ "description": "Rates applied to an invocation and its resolved dollar cost.",
"required": ["price_per_million_in", "price_per_million_out", "total"],
"properties": {
+ "price_per_audio_minute": {
+ "type": ["number", "null"],
+ "format": "float",
+ "description": "Price per audio minute (USD), absent for token billing."
+ },
"price_per_million_in": {
"type": "number",
"format": "float",
- "description": "Price per million input tokens (USD)."
+ "description": "Price per million input tokens (USD); zero for audio billing."
},
"price_per_million_out": {
"type": "number",
"format": "float",
- "description": "Price per million output tokens (USD)."
+ "description": "Price per million output tokens (USD); zero for audio billing."
},
"total": {
"type": "number",
"format": "float",
- "description": "Total cost of the completion (USD)."
+ "description": "Total cost (USD)."
}
}
},
@@ -4312,21 +4328,26 @@
"SetPricingRequest": {
"type": "object",
"description": "Request body for [`set_pricing_handler`].",
- "required": ["model", "price_per_mil_in", "price_per_mil_out"],
+ "required": ["model"],
"properties": {
"model": {
"type": "string",
"description": "The model api id to (re)price."
},
+ "price_per_audio_minute": {
+ "type": ["number", "null"],
+ "format": "float",
+ "description": "Price per minute of audio (USD), or null for token-only pricing."
+ },
"price_per_mil_in": {
- "type": "number",
+ "type": ["number", "null"],
"format": "float",
- "description": "New price per million input tokens (USD)."
+ "description": "New price per million input tokens (USD). Required for token pricing."
},
"price_per_mil_out": {
- "type": "number",
+ "type": ["number", "null"],
"format": "float",
- "description": "New price per million output tokens (USD)."
+ "description": "New price per million output tokens (USD). Required for token pricing."
}
}
},
@@ -4790,28 +4811,33 @@
},
"Usage": {
"type": "object",
- "description": "The token usage and resolved cost of a single completion.",
+ "description": "Measured usage for one invocation.",
"required": ["input_tokens", "output_tokens", "model", "created_at"],
"properties": {
+ "audio_seconds": {
+ "type": ["number", "null"],
+ "format": "double",
+ "description": "Audio duration in seconds, absent for token billing."
+ },
"created_at": {
"type": "string",
"format": "date-time",
- "description": "When the completion was recorded."
+ "description": "Recording timestamp."
},
"input_tokens": {
"type": "integer",
- "format": "int32",
- "description": "Tokens consumed by the input.",
+ "format": "int64",
+ "description": "Input tokens; zero for audio billing.",
"minimum": 0
},
"model": {
"type": "string",
- "description": "The model api id (e.g. `claude-opus-4-8`)."
+ "description": "Provider model identifier."
},
"output_tokens": {
"type": "integer",
- "format": "int32",
- "description": "Tokens generated in the output.",
+ "format": "int64",
+ "description": "Output tokens; zero for audio billing.",
"minimum": 0
},
"price": {
@@ -4821,7 +4847,7 @@
},
{
"$ref": "#/components/schemas/Price",
- "description": "Resolved price, or `None` when the model had no pricing at record time."
+ "description": "Applied pricing, if known."
}
]
}
@@ -4859,7 +4885,7 @@
},
"UsageSummary": {
"type": "object",
- "description": "The result of a usage query: per-feature breakdown plus a grand total.",
+ "description": "Per-feature breakdown and grand total.",
"required": ["entries", "total"],
"properties": {
"entries": {
@@ -4872,7 +4898,7 @@
"total": {
"type": "number",
"format": "float",
- "description": "Grand total cost across all features (USD)."
+ "description": "Grand total (USD)."
}
}
},
diff --git a/packages/sdk/specs/storage.json b/packages/sdk/specs/storage.json
index d0e667ea69d..1340f51280a 100644
--- a/packages/sdk/specs/storage.json
+++ b/packages/sdk/specs/storage.json
@@ -6284,6 +6284,116 @@
}
}
},
+ "/dictation/transcribe": {
+ "post": {
+ "tags": ["dictation"],
+ "summary": "Transcribe a transient recording with OpenAI Whisper.",
+ "description": "Available to every signed-in user on every plan; does not consume chat\ncredits. Audio and transcripts are never persisted.",
+ "operationId": "transcribe_dictation",
+ "parameters": [
+ {
+ "name": "language",
+ "in": "query",
+ "description": "ISO 639-1 language hint",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "Encoded WebM, MP4, Ogg, or WAV audio up to 8 MiB and five minutes",
+ "content": {
+ "audio/webm": {
+ "schema": {
+ "type": "string",
+ "format": "binary",
+ "description": "OpenAPI representation of the raw encoded audio body extracted as `Bytes`."
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TranscribeResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Empty, oversized, or malformed request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Missing or invalid credentials",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Only signed-in users may dictate",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "413": {
+ "description": "Body exceeds 8 MiB"
+ },
+ "415": {
+ "description": "Unsupported audio container",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Per-user hourly rate limit exceeded"
+ },
+ "502": {
+ "description": "Provider failure",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "Transcription capacity exhausted; retry after the Retry-After delay",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/documents": {
"get": {
"tags": ["document"],
@@ -29758,6 +29868,17 @@
}
}
},
+ "TranscribeResponse": {
+ "type": "object",
+ "description": "Transcription result.",
+ "required": ["text"],
+ "properties": {
+ "text": {
+ "type": "string",
+ "description": "Recognized text."
+ }
+ }
+ },
"TranscriptSegmentRequest": {
"type": "object",
"description": "A transcript segment from LiveKit Inference STT.",
diff --git a/packages/sdk/src/coverage/skipped.ts b/packages/sdk/src/coverage/skipped.ts
index 3d61791dece..097d3a1285d 100644
--- a/packages/sdk/src/coverage/skipped.ts
+++ b/packages/sdk/src/coverage/skipped.ts
@@ -322,6 +322,8 @@ export const storageExcluded = [
'postItemsSoupAstGrouped',
'removeBotFromChannelByBot',
'resolveChannelMessage',
+ // Composer dictation is an app-internal, user-only upload flow.
+ 'transcribeDictation',
'uploadExtractFolderHandler',
'uploadFolderHandler',
'upsertHistoryHandler',
diff --git a/services/document_cognition_service/src/api/swagger.rs b/services/document_cognition_service/src/api/swagger.rs
index 7f51459e3ae..223f49e20d6 100644
--- a/services/document_cognition_service/src/api/swagger.rs
+++ b/services/document_cognition_service/src/api/swagger.rs
@@ -219,11 +219,11 @@ use utoipa::OpenApi;
ai_usage_api::UsageRequest,
ai_usage_api::SetPricingRequest,
ai_usage_api::ErrorBody,
- ai_usage::UsageSummary,
- ai_usage::FeatureUsage,
- ai_usage::CompletionUsage,
- ai_usage::Usage,
- ai_usage::Price,
+ ai_usage::inbound::models::UsageSummary,
+ ai_usage::inbound::models::FeatureUsage,
+ ai_usage::inbound::models::CompletionUsage,
+ ai_usage::inbound::models::Usage,
+ ai_usage::inbound::models::Price,
ai_usage::AiFeature,
// AI projections
diff --git a/services/document_storage_service/Cargo.toml b/services/document_storage_service/Cargo.toml
index 5ce675ea013..ad35ef06017 100644
--- a/services/document_storage_service/Cargo.toml
+++ b/services/document_storage_service/Cargo.toml
@@ -27,6 +27,7 @@ local_auth = ["macro_authorization/local_auth"]
location_check = []
[dependencies]
+dictation = { path = "../../crates/dictation", features = ["inbound", "outbound"] }
agent_session = { path = "../../crates/agent_session", features = ["outbound"] }
activity = { path = "../../crates/activity" }
ai_tools = { path = "../../crates/ai_tools" }
diff --git a/services/document_storage_service/src/api.rs b/services/document_storage_service/src/api.rs
index c1cc5b10cfd..b2d6986b821 100644
--- a/services/document_storage_service/src/api.rs
+++ b/services/document_storage_service/src/api.rs
@@ -58,7 +58,7 @@ pub async fn setup_and_serve(state: ApiContext) -> anyhow::Result<()> {
},
validate_api_version,
))
- .layer(macro_cors::cors_layer())
+ .layer(macro_cors::cors_layer().expose_headers([axum::http::header::RETRY_AFTER]))
.layer(CompressionLayer::new().gzip(true)),
)
// The health router is attached here so we don't attach the logging middleware to it
@@ -113,6 +113,10 @@ fn api_router(state: ApiContext) -> Router {
);
let internal_router = Router::new()
+ .nest(
+ "/dictation",
+ dictation::inbound::axum_router::dictation_router(state.dictation_state.clone()),
+ )
.nest(
"/github",
github::inbound::github_sync_router::github_sync_router(
diff --git a/services/document_storage_service/src/api/context.rs b/services/document_storage_service/src/api/context.rs
index c32d518c1b7..add28ce3c91 100644
--- a/services/document_storage_service/src/api/context.rs
+++ b/services/document_storage_service/src/api/context.rs
@@ -554,8 +554,19 @@ pub(crate) type DssSseStreamService =
pub(crate) type DssSseStreamState =
WebhookStreamRouterState;
+/// Type alias for the dictation router state; shares the webhook Redis limiter.
+pub(crate) type DssDictationState = dictation::inbound::axum_router::DictationRouterState<
+ dictation::domain::DictationServiceImpl<
+ dictation::outbound::WhisperTranscriber,
+ dictation::outbound::SymphoniaRecordingInspector,
+ >,
+ DssWebhookRateLimiter,
+ AuthorizationService,
+>;
+
#[derive(Clone, FromRef)]
pub(crate) struct ApiContext {
+ pub dictation_state: DssDictationState,
pub db: PgPool,
pub readonly_db: ReadOnlyPool,
pub redis_client: Arc,
diff --git a/services/document_storage_service/src/api/swagger.rs b/services/document_storage_service/src/api/swagger.rs
index 9522795a12b..f83f3889d0f 100644
--- a/services/document_storage_service/src/api/swagger.rs
+++ b/services/document_storage_service/src/api/swagger.rs
@@ -150,6 +150,7 @@ use utoipa::OpenApi;
terms_of_service = "https://macro.com/terms",
),
paths(
+ dictation::inbound::axum_router::transcribe_handler,
health::health_handler,
calendar_events::inbound::axum_router::list_occurrences,
calendar_events::inbound::axum_router::mention_previews,
@@ -720,6 +721,7 @@ use utoipa::OpenApi;
webhook::domain::models::WebhookFilter,
webhook::domain::models::WebhookStatus,
webhook::domain::models::WebhookValidationTestEvent,
+ dictation::inbound::axum_router::TranscribeResponse,
DocumentSubType,
diff --git a/services/document_storage_service/src/config.rs b/services/document_storage_service/src/config.rs
index 4a75de0c4c1..78f2e5fdc1d 100644
--- a/services/document_storage_service/src/config.rs
+++ b/services/document_storage_service/src/config.rs
@@ -1,4 +1,5 @@
use anyhow::Context;
+pub use dictation::outbound::OpenaiApiKey;
use macro_auth::InternalApiKey;
pub use macro_env::Environment;
use macro_env_var::{env_vars, maybe_env_vars};
@@ -34,10 +35,6 @@ env_vars! {
pub struct LivekitServerUrl;
pub struct LivekitApiKey;
pub struct LivekitApiSecret;
- /// OpenAI API key used to generate task-dedup embeddings. Required —
- /// injected as `OPENAI_API_KEY` from the `openai-key` secret by the
- /// infra stack, the same way `document_cognition_service` consumes it.
- pub struct OpenaiApiKey;
/// Cohere API key used by the task-dedup reranker. Required — injected
/// as `COHERE_API_KEY`, following the same pattern as `OPENAI_API_KEY`.
pub struct CohereApiKey;
@@ -108,6 +105,7 @@ pub struct Config {
pub livekit_server_url: LivekitServerUrl,
pub livekit_api_key: LivekitApiKey,
pub livekit_api_secret: LivekitApiSecret,
+ /// Shared server credential for task embeddings and Whisper, supplied by Doppler.
pub openai_api_key: OpenaiApiKey,
pub cohere_api_key: CohereApiKey,
pub github_webhook_secret_key: LocalOrRemoteSecret,
diff --git a/services/document_storage_service/src/main.rs b/services/document_storage_service/src/main.rs
index 7bdd7a8c52f..a4349aab957 100644
--- a/services/document_storage_service/src/main.rs
+++ b/services/document_storage_service/src/main.rs
@@ -942,20 +942,31 @@ async fn run() -> anyhow::Result<()> {
let sqs_client = Arc::new(sqs_client);
let conn_gateway_client = Arc::new(conn_gateway_client);
- // The OpenAI key is injected as the required `OPENAI_API_KEY` env var
- // (resolved from the `openai-key` secret at deploy time by the infra stack),
- // the same way `document_cognition_service` consumes it. Fail fast if it's
- // empty so the service never starts with a broken task-dedup embedder.
+ // MacroConfig reads the shared OPENAI_API_KEY from Doppler's APP_SECRETS_JSON
+ // or the local environment. Validate once before constructing consumers.
let openai_api_key = config.openai_api_key.as_ref().to_owned();
anyhow::ensure!(
!openai_api_key.trim().is_empty(),
- "OpenAI API key is required for task dedup embeddings",
+ "OpenAI API key is required for task dedup embeddings and dictation",
);
let cohere_api_key = config.cohere_api_key.as_ref().to_owned();
anyhow::ensure!(
!cohere_api_key.trim().is_empty(),
"Cohere API key is required for task dedup reranking",
);
+ let dictation_state = dictation::inbound::axum_router::DictationRouterState::new(
+ dictation::domain::DictationServiceImpl::new(
+ dictation::outbound::WhisperTranscriber::new(&config.openai_api_key)?,
+ dictation::outbound::SymphoniaRecordingInspector,
+ ai_usage::pg_recorder(db.clone()),
+ ),
+ RateLimitServiceImpl {
+ repo: RedisRateLimitAdapter {
+ redis: redis_client.clone(),
+ },
+ },
+ authorization_state.clone(),
+ );
let task_dedup_service = Arc::new(TaskDedupService::new(
TextEmbedding3Small::new(openai_api_key),
PgTaskVectorDb::new(db.clone()),
@@ -1473,6 +1484,7 @@ async fn run() -> anyhow::Result<()> {
));
let api_context = ApiContext {
+ dictation_state,
contacts_ingress: contacts_ingress.clone(),
soup_router_state: SoupRouterState::from_arc(
soup_service.clone(),
diff --git a/services/email_service/Cargo.toml b/services/email_service/Cargo.toml
index 0c762cd515e..ccab98ca519 100644
--- a/services/email_service/Cargo.toml
+++ b/services/email_service/Cargo.toml
@@ -110,7 +110,7 @@ gmail_client = { path = "../../crates/gmail_client" }
google_token = { path = "../../crates/google_token" }
html-escape = { workspace = true }
http-body-util = { workspace = true }
-infer = "0.19.0"
+infer = { workspace = true }
item_filters = { path = "../../crates/item_filters" }
lol_html = { workspace = true }
macro_auth = { path = "../../crates/macro_auth" }