@alexkroman1/aai-cli 6.10.0 → 6.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scaffold/CLAUDE.md +58 -0
- package/dist/scaffold/package.json +3 -3
- package/dist/scaffold/server.mjs +12 -3
- package/dist/scaffold/vite.config.ts +1 -1
- package/dist/templates/call-audit/agent.test.ts +965 -0
- package/dist/templates/call-audit/agent.ts +158 -0
- package/dist/templates/call-audit/client.tsx +235 -0
- package/dist/templates/call-audit/workflows/audit.ts +305 -0
- package/dist/templates/call-audit/workflows/ingest.ts +259 -0
- package/dist/templates/call-audit/workflows/media.ts +647 -0
- package/dist/templates/call-audit/workflows/summarize.ts +206 -0
- package/dist/templates/call-audit/workflows/sync-api.ts +44 -0
- package/dist/templates/call-audit/workflows/temp-media.ts +138 -0
- package/dist/templates/recap-workflow/agent.test.ts +11 -3
- package/dist/templates/recap-workflow/workflows/recap.ts +19 -8
- package/dist/templates/spoken-summary/agent.test.ts +343 -0
- package/dist/templates/spoken-summary/agent.ts +142 -0
- package/dist/templates/spoken-summary/client.tsx +225 -0
- package/dist/templates/spoken-summary/workflows/summarize.ts +242 -0
- package/dist/templates/spoken-summary/workflows/transcribe.ts +145 -0
- package/dist/templates/transcription-workflow/agent.test.ts +241 -18
- package/dist/templates/transcription-workflow/agent.ts +20 -6
- package/dist/templates/transcription-workflow/workflows/batch.ts +75 -173
- package/dist/templates/transcription-workflow/workflows/normalize.ts +343 -0
- package/dist/templates/transcription-workflow/workflows/stream.ts +6 -4
- package/dist/templates/transcription-workflow/workflows/sync-api.ts +26 -94
- package/dist/templates/transcription-workflow/workflows/transcribe.ts +23 -14
- package/dist/templates/transcription-workflow/workflows/wav.ts +31 -0
- package/package.json +3 -3
package/dist/scaffold/CLAUDE.md
CHANGED
|
@@ -466,6 +466,64 @@ Three rules come with it:
|
|
|
466
466
|
`stepGenerate` already goes through this, so a step that only calls a model gets
|
|
467
467
|
it for free.
|
|
468
468
|
|
|
469
|
+
### A step can SPEAK, and store the file it made
|
|
470
|
+
|
|
471
|
+
A workflow whose answer is a FILE — a summary read aloud, a rendered image, a
|
|
472
|
+
generated PDF — needs two things a first draft reaches for and does not find.
|
|
473
|
+
Both are on `@alexkroman1/aai/utils`, and `spoken-summary` is the template that
|
|
474
|
+
shows the whole round trip.
|
|
475
|
+
|
|
476
|
+
```ts no-check
|
|
477
|
+
import { stepSpeak, writeUpload } from "@alexkroman1/aai/utils";
|
|
478
|
+
|
|
479
|
+
export async function narrate(script: string) {
|
|
480
|
+
"use step";
|
|
481
|
+
|
|
482
|
+
const spoken = await stepSpeak(script, { voice: "jane" });
|
|
483
|
+
const stored = await writeUpload(spoken.audio, { name: "summary.wav", type: "audio/wav" });
|
|
484
|
+
return { audio: stored.id, durationMs: spoken.durationMs };
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
**`stepSpeak` is `stepGenerate` for the voice.** A step is handed no
|
|
489
|
+
`ToolContext`, so the provider stack your `agent()` declares is not in scope —
|
|
490
|
+
and the session TTS surface would not help anyway: it is an event stream wired
|
|
491
|
+
into a live pipeline's playback, and a step has no turn to be part of and has to
|
|
492
|
+
return a value. So this is the smaller thing: text in, the whole utterance out
|
|
493
|
+
as a WAV, on the same `ASSEMBLYAI_API_KEY` everything else uses. Voices come
|
|
494
|
+
from `ASSEMBLYAI_TTS_VOICES` (`@alexkroman1/aai/tts`) — read that list rather
|
|
495
|
+
than typing an id, because a wrong one is refused *after* the socket opens and
|
|
496
|
+
produces silence rather than an error.
|
|
497
|
+
|
|
498
|
+
**`writeUpload` is `readUpload`'s other direction, and you need it.** A run's
|
|
499
|
+
output is read back as JSON, so audio cannot travel in one — the same rule that
|
|
500
|
+
keeps an uploaded recording's bytes out of a run's INPUT, arriving at the other
|
|
501
|
+
end of the run. Store the bytes, return the **id**, and let the page fetch it
|
|
502
|
+
with `api.download(id)`.
|
|
503
|
+
|
|
504
|
+
Three rules come with it:
|
|
505
|
+
|
|
506
|
+
- **Speak and store in ONE step.** A step is journaled by its return value, so
|
|
507
|
+
an id is replayed on a resume and bytes are not. Split in two, the audio
|
|
508
|
+
crosses the queue between them every time the run resumes.
|
|
509
|
+
- **A retried step writes a SECOND upload** and abandons the first — the store
|
|
510
|
+
cannot know two calls meant one file. That is the price of the step being
|
|
511
|
+
retryable at all, and it is the right trade.
|
|
512
|
+
- **Name and TYPE what you store.** The byte route serves the `type` it was
|
|
513
|
+
given, and a browser will not play inline a file it was handed as
|
|
514
|
+
`application/octet-stream`.
|
|
515
|
+
|
|
516
|
+
On the page, `api.download(id)` answers a `Blob`, not a URL — the byte route
|
|
517
|
+
takes the same bearer every other route does, and neither `<audio src>` nor
|
|
518
|
+
`<a href>` can send one, so a page built on a URL works in `aai dev` and 401s
|
|
519
|
+
once the agent has a token. `URL.createObjectURL(blob)` is what those elements
|
|
520
|
+
take; revoke it when the id changes.
|
|
521
|
+
|
|
522
|
+
Test both with `stubSpeech()` and `stubUploads(files, { writable: true })`
|
|
523
|
+
(`@alexkroman1/aai/testing`). The write half is opt-in on purpose: a store that
|
|
524
|
+
silently accepted writes could not fail a spec whose step stored a file nobody
|
|
525
|
+
meant it to.
|
|
526
|
+
|
|
469
527
|
### A builtin's failure is its RESULT, so narrow it
|
|
470
528
|
|
|
471
529
|
`webSearch`, `visitWebpage` and `fetchJson` (`@alexkroman1/aai/tools`) answer
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"publish:agent": "aai publish"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@alexkroman1/aai": "^6.
|
|
17
|
-
"@alexkroman1/aai-ui": "^6.
|
|
16
|
+
"@alexkroman1/aai": "^6.11.0",
|
|
17
|
+
"@alexkroman1/aai-ui": "^6.11.0",
|
|
18
18
|
"@workflow/world-postgres": "4.3.3",
|
|
19
19
|
"react": "^19.2.8",
|
|
20
20
|
"react-dom": "^19.2.8",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"zod": "^4.4.3"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@alexkroman1/aai-cli": "^6.
|
|
26
|
+
"@alexkroman1/aai-cli": "^6.11.0",
|
|
27
27
|
"@tailwindcss/vite": "^4.3.3",
|
|
28
28
|
"@types/node": "^26.2.0",
|
|
29
29
|
"@types/react": "^19.2.18",
|
package/dist/scaffold/server.mjs
CHANGED
|
@@ -144,9 +144,18 @@ await server.listen(Number(process.env.PORT ?? 3000), host);
|
|
|
144
144
|
console.log(`${agent.name} listening on http://${host ?? "127.0.0.1"}:${server.port}`);
|
|
145
145
|
|
|
146
146
|
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
147
|
-
|
|
147
|
+
// A SYNCHRONOUS listener. An `async` one hands its promise to `process`,
|
|
148
|
+
// which discards what a listener returns — so a `close()` that rejects would
|
|
149
|
+
// surface as an unhandled rejection, i.e. a crash with a stack trace on
|
|
150
|
+
// Ctrl-C, instead of the non-zero exit a failed shutdown should be.
|
|
151
|
+
process.once(signal, () => {
|
|
148
152
|
// close() shuts the runtime down too — no separate runtime.shutdown().
|
|
149
|
-
|
|
150
|
-
|
|
153
|
+
server.close().then(
|
|
154
|
+
() => process.exit(0),
|
|
155
|
+
(error) => {
|
|
156
|
+
console.error(`shutdown failed: ${error?.message ?? error}`);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
},
|
|
159
|
+
);
|
|
151
160
|
});
|
|
152
161
|
}
|