Repository navigation
feat(voice): audio library and provider credential commands (Voice Automation beta) - #25
Conversation
… exit codes voice_not_enabled exits 6 and gate_limit_reached exits 7 whatever their HTTP status, so scripts can tell a missing Voice Automation beta enrollment or a reached voice limit from other authorization and payment failures. Add the voice_asset_failed condition (exit 13) for audio that fails processing while a command waits for it.
Add voice audio upload|tts|list|view|update|delete|preview and voice credential add|list|view|verify|delete for the Voice Automation beta (calls.voice-automation), contract revision voice-audio-v1. - upload detects the content type from the extension and refuses other types, empty files and files over 16 MB before any request. The bytes go to the returned upload URL with only its headers and no credential; the asset is then completed. --wait polls until ready or failed. - credential add reads the key from the variable named by --key-env (default POLYMORFA_VOICE_PROVIDER_KEY) or piped stdin, never an argument, refuses a terminal, and registers the key for redaction. - delete commands confirm or take --yes. The pinned SDK (94bfd09) has no client.voice and git pins cannot install newer SDK commits since the SDK became a workspace, so src/sdk/voice.ts sends the documented requests through the organization client's raw transport, mirroring client.voice in polymorfa/sdks f0f3c07.
README section with the audio library and provider credential commands, key input rules and voice exit codes (6 voice_not_enabled, 7 gate_limit_reached, 13 voice_asset_failed); command research for contract voice-audio-v1 and the SDK pin situation; a skill note on beta errors and provider key handling.
|
Warning Review limit reached
Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing. Next included review available in 25 minutes. View limit detailsLimit details: You’ve used the included review currently available. Your 73 included PR review attempts over the past 7 days set your current allowance at 1 review per hour. Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (24)
Comment |
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e03082495a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| {cause: error, code: 'connection_error'}, | ||
| ) | ||
| } finally { | ||
| clearTimeout(timer) |
There was a problem hiding this comment.
Keep the timeout active while reading transfer bodies
When a preview or failed upload endpoint sends response headers and then stalls, fetch() resolves as soon as the headers arrive and this finally clears the abort timer. The subsequent response.arrayBuffer() or safeBody(response) read can therefore hang indefinitely, ignoring both --timeout and the 120-second default. Keep the controller and timer alive until the response body has been fully consumed or cancelled.
Useful? React with 👍 / 👎.
| const bytes = new Uint8Array(await response.arrayBuffer()) | ||
| if (bytes.byteLength > maxBytes) throw tooLargePreview(maxBytes) |
There was a problem hiding this comment.
Enforce the preview limit while streaming
When the preview response omits Content-Length, understates it, or is transparently decompressed to a larger size, this buffers the entire response before checking maxBytes. Thus the documented 32 MiB limit does not actually bound memory use, and a sufficiently large capability response can exhaust the CLI process before tooLargePreview() runs. Read the body incrementally and cancel it as soon as the accumulated bytes exceed the limit.
Useful? React with 👍 / 👎.
…d preview downloads while streaming
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 776e50266f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let current = asset | ||
| // Like the SDK's waitUntilReady: read first, then sleep between reads. | ||
| while (current.data.status !== 'ready' && current.data.status !== 'failed') { | ||
| const response = await client.retrieveAudio(current.data.id) |
There was a problem hiding this comment.
Bound each status poll by the wait deadline
When the asset is still processing and retrieveAudio() stalls, this request begins before the deadline is checked, so --wait-timeout does not stop the command at the promised time; for example, --wait-timeout 1 can remain blocked until the request's separate network timeout expires. Check the deadline before every poll and ensure the request itself is bounded by the remaining wait budget.
Useful? React with 👍 / 👎.
… t3code/voice-audio-library
…rary # Conflicts: # README.md # src/errors/present.ts # test/errors/present.test.ts
…rary # Conflicts: # README.md # package.json
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1750c11c59
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| apiKey, | ||
| label: flags.label, | ||
| provider: flags.provider, | ||
| ...(projectId === undefined || projectId.length === 0 ? {} : {projectId}), |
There was a problem hiding this comment.
Reject an explicitly empty credential project
When --project "$PROJECT" expands to an empty or whitespace-only value, this condition omits projectId, so an add intended to be project-scoped instead creates a team-wide credential that every project can use. Because omitting --project deliberately selects team-wide scope, an explicitly supplied blank value should fail validation rather than silently broaden the credential's scope.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3ff9e042ea
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| try { | ||
| const info = await handle.stat() | ||
| if (info.size > MAX_TEXT_FILE_BYTES) throw textTooLarge() | ||
| return (await handle.readFile('utf8')).replace(/\r?\n$/, '') |
There was a problem hiding this comment.
Enforce the text-file limit while reading
When --text-file names a streaming or non-regular path such as /dev/stdin or a FIFO, stat() commonly reports a size of zero, after which readFile() buffers until EOF without enforcing MAX_TEXT_FILE_BYTES. A large or unending source therefore bypasses the advertised 64 KiB bound and can exhaust memory or hang the command before validateTtsText() runs. Read the handle incrementally and stop once the byte limit is exceeded, as the - stdin path already does.
Useful? React with 👍 / 👎.
The Voice Automation beta needs CLI commands for its audio library and provider credentials. This PR adds
polymorfa voice audioupload, TTS, list, view, update, preview and delete commands, pluspolymorfa voice credentialadd, list, view, verify and delete. It targetsdev; Calls remains unreleased, and enrolled teams need the deployed API and their existing credentials/scopes before these commands can work.Upload reads and validates the local file before creating an asset, then uses the typed SDK Voice resource to transfer bytes to the signed URL without an API credential or redirect. Preview download is bounded to 32 MiB and refuses redirects; network errors and storage refusals omit the signed link, untrusted response text and nested causes. Provider keys come from
POLYMORFA_VOICE_PROVIDER_KEY, an explicitly named environment variable, or piped stdin; no flag accepts a key value. The CLI redacts keys from errors and prints only their fingerprint.--waitdistinguishes ready, failed and timed-out assets. Help, command research and README examples describe beta access and exit codes.The branch normally merges CLI
devat4a730e81586663adb05f832f15b8d9f1d1b1e5acand pins published@polymorfa/sdk@0.1.0-dev.20260923144429with integritysha512-U/JQY4f5hE9LZFPQaOHSH8bSXXTNKFmd5ZtU6mpS7HmMcQH89eJlFfquTI3bgLtHJiyt4j/jt1wp8ULVv6IY7Q==, from SDKdevmerge75ac1bc478b9fd8da8b2cd393bd0d5a07fb79197(Voice #279 and upload redaction #292). The API source is monorepodevmerge087d0e34b53eec82ebc5d04c5b4c75eaaa556b4ffrom #227.Verification
A clean Node 22
npm ciandnpm run verifypass: formatting, lint, typecheck, 764 tests in 82 files, build, package dry run and production audit with zero findings. Tests cover upload/credential success and refusal paths, no credential on signed transfer, validation before requests, wait results, preview bounds and timeouts, and full signed-link redaction from inspected errors. No live API, provider call, deployment or production rollout was exercised.Contract and release assessment