feat(calls): move transcript to agent#2377
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR adds agent-to-backend transcript posting using a shared secret: the transcription agent now sends transcript segments via HTTP (httpx) to an internal endpoint authenticated with an Changes
Possibly related PRs
🚥 Pre-merge checks | ✅ 1 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@agents/transcription/transcriber.py`:
- Around line 58-75: Replace the ephemeral uuid4() segmentId with a stable id
derived from the provider/message identifier (e.g., use an existing
provider_message_id or compute a deterministic hash of provider_message_id +
participant + startedAt) so retries are idempotent; then wrap the
self.http_client.post call in a small bounded retry with exponential backoff
(e.g., 3 attempts with increasing delays) and only retry on transient errors
(timeouts/5xx/network), calling resp.raise_for_status() and logging the final
failure with the segmentId and error; refer to the segment construction,
segmentId, self.http_client.post, MACRO_API_URL, channel_id and
INTERNAL_CALL_SECRET to locate where to change.
In `@infra/stacks/cloud-storage-service/index.ts`:
- Around line 280-282: The transcription agent Docker setup is missing the
INTERNAL_CALL_SECRET env var used by the agent (it reads
os.environ.get("INTERNAL_CALL_SECRET", "")), causing empty x-macro-internal-call
headers; update agents/transcription/Dockerfile to accept and pass the same
secret from AWS Secrets Manager into the container (either as a build-arg and/or
an ENV) so the running container has INTERNAL_CALL_SECRET set, and ensure the
deployment that creates the agent image injects the secret value retrieved via
the same INTERNAL_CALL_SECRET/aws.secretsmanager.getSecretVersionOutput(...)
used for CloudStorageService; this will align the agent with CloudStorageService
which expects the header.
In `@rust/cloud-storage/call/src/domain/service.rs`:
- Around line 45-49: The compare in validate_internal_call currently uses ==
which short-circuits and creates a timing side channel; update
validate_internal_call to perform a constant-time byte comparison by using
subtle::ConstantTimeEq (e.g., compare secret.as_bytes() and token.as_bytes()
with ct_eq(...).into()) inside the existing as_deref().is_some_and closure, and
ensure the call crate's Cargo.toml includes the subtle dependency if not already
present.
In `@rust/cloud-storage/document_storage_service/src/config.rs`:
- Around line 75-78: Startup should fail fast if a live transcription agent is
configured but the internal secret is missing: add a validation during
initialization that checks if LivekitTranscriptionAgentName is set (non-empty)
and InternalCallSecret is missing or empty, and abort startup with a clear
error; update the code path that currently calls dispatch_transcription_agent()
to rely on this check rather than allowing dispatch when
validate_internal_call() would later reject requests, referencing the symbols
InternalCallSecret, validate_internal_call(), dispatch_transcription_agent(),
and LivekitTranscriptionAgentName so the check is added during config/bootstrap
initialization.
In `@rust/cloud-storage/document_storage_service/src/main.rs`:
- Around line 363-375: The code unconditionally mounts InternalCallRouterState
despite InternalCallSecret being optional, so processes can start without a
secret and then fail-close on /call/.../transcript; modify the wiring in main.rs
to require the secret before creating/mounting InternalCallRouterState: after
constructing internal_call_secret (config::InternalCallSecret::new()), if it is
None do not call CallServiceImpl::with_internal_call_secret and do not create
InternalCallRouterState (InternalCallRouterState::new) nor add
call_internal_state to the router; alternatively, if you prefer failing fast,
return an error and abort startup when internal_call_secret is None so
CallServiceImpl and InternalCallRouterState are only created when a valid secret
exists (use the existing symbols InternalCallSecret, CallServiceImpl,
with_internal_call_secret, and InternalCallRouterState to locate the relevant
code).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 0adb9445-b431-49cf-877b-3c7b1606aea3
📒 Files selected for processing (12)
agents/transcription/requirements.txtagents/transcription/transcriber.pyinfra/stacks/cloud-storage-service/Pulumi.dev.yamlinfra/stacks/cloud-storage-service/Pulumi.prod.yamlinfra/stacks/cloud-storage-service/index.tsrust/cloud-storage/call/src/domain/ports.rsrust/cloud-storage/call/src/domain/service.rsrust/cloud-storage/call/src/inbound/axum_router.rsrust/cloud-storage/document_storage_service/src/api/context.rsrust/cloud-storage/document_storage_service/src/api/mod.rsrust/cloud-storage/document_storage_service/src/config.rsrust/cloud-storage/document_storage_service/src/main.rs
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@js/app/packages/service-clients/service-storage/openapi.json`:
- Line 738: The OpenAPI spec documents the required x-macro-internal-call header
in prose but doesn't declare it as an auth requirement, causing client
generation/runtime mismatch; fix by adding a components.securitySchemes entry
for an apiKey in the header named "x-macro-internal-call" and reference that
scheme in the operation's security array (or global security) for the
transcript-segments endpoint that mentions "Receives transcript segments…" so
generated clients and docs treat the header as required; alternatively, add a
header parameter entry for "x-macro-internal-call" on the operation if you
prefer parameter-based requirements, but ensure the components.securitySchemes
name and the operation security reference match exactly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: fde3c44f-4c58-4782-8d36-055d86e4b656
⛔ Files ignored due to path filters (1)
js/app/packages/service-clients/service-storage/generated/zod.tsis excluded by!**/generated/**
📒 Files selected for processing (5)
.env-local.enc.env-localdev.encagents/transcription/transcriber.pyjs/app/packages/service-clients/service-storage/openapi.jsonrust/cloud-storage/document_storage_service/src/main.rs
No description provided.