@dxos/pipeline-transcription 0.0.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/lib/neutral/chunk-Y44GOMGN.mjs +22 -0
- package/dist/lib/neutral/chunk-Y44GOMGN.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +886 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/testing/index.mjs +192 -0
- package/dist/lib/neutral/testing/index.mjs.map +7 -0
- package/dist/types/src/PipelineConfig.d.ts +49 -0
- package/dist/types/src/PipelineConfig.d.ts.map +1 -0
- package/dist/types/src/PipelineConfig.test.d.ts +2 -0
- package/dist/types/src/PipelineConfig.test.d.ts.map +1 -0
- package/dist/types/src/PipelineRuntime.d.ts +46 -0
- package/dist/types/src/PipelineRuntime.d.ts.map +1 -0
- package/dist/types/src/PipelineRuntime.test.d.ts +2 -0
- package/dist/types/src/PipelineRuntime.test.d.ts.map +1 -0
- package/dist/types/src/Stage.d.ts +80 -0
- package/dist/types/src/Stage.d.ts.map +1 -0
- package/dist/types/src/TranscriptEvent.d.ts +23 -0
- package/dist/types/src/TranscriptEvent.d.ts.map +1 -0
- package/dist/types/src/asr/audio-recorder.d.ts +47 -0
- package/dist/types/src/asr/audio-recorder.d.ts.map +1 -0
- package/dist/types/src/asr/index.d.ts +5 -0
- package/dist/types/src/asr/index.d.ts.map +1 -0
- package/dist/types/src/asr/pipeline.d.ts +42 -0
- package/dist/types/src/asr/pipeline.d.ts.map +1 -0
- package/dist/types/src/asr/sentence-buffer.d.ts +25 -0
- package/dist/types/src/asr/sentence-buffer.d.ts.map +1 -0
- package/dist/types/src/asr/sentence-buffer.test.d.ts +2 -0
- package/dist/types/src/asr/sentence-buffer.test.d.ts.map +1 -0
- package/dist/types/src/asr/transcriber.d.ts +115 -0
- package/dist/types/src/asr/transcriber.d.ts.map +1 -0
- package/dist/types/src/asr/transcriber.test.d.ts +2 -0
- package/dist/types/src/asr/transcriber.test.d.ts.map +1 -0
- package/dist/types/src/asr/util.d.ts +2 -0
- package/dist/types/src/asr/util.d.ts.map +1 -0
- package/dist/types/src/dispatch.d.ts +19 -0
- package/dist/types/src/dispatch.d.ts.map +1 -0
- package/dist/types/src/dispatch.test.d.ts +2 -0
- package/dist/types/src/dispatch.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +11 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/live.d.ts +24 -0
- package/dist/types/src/live.d.ts.map +1 -0
- package/dist/types/src/live.test.d.ts +2 -0
- package/dist/types/src/live.test.d.ts.map +1 -0
- package/dist/types/src/lookup.d.ts +35 -0
- package/dist/types/src/lookup.d.ts.map +1 -0
- package/dist/types/src/lookup.test.d.ts +2 -0
- package/dist/types/src/lookup.test.d.ts.map +1 -0
- package/dist/types/src/model-routing.d.ts +12 -0
- package/dist/types/src/model-routing.d.ts.map +1 -0
- package/dist/types/src/pipeline-integration.test.d.ts +2 -0
- package/dist/types/src/pipeline-integration.test.d.ts.map +1 -0
- package/dist/types/src/stages/correction-llm.d.ts +14 -0
- package/dist/types/src/stages/correction-llm.d.ts.map +1 -0
- package/dist/types/src/stages/correction-llm.test.d.ts +2 -0
- package/dist/types/src/stages/correction-llm.test.d.ts.map +1 -0
- package/dist/types/src/stages/correction.d.ts +29 -0
- package/dist/types/src/stages/correction.d.ts.map +1 -0
- package/dist/types/src/stages/correction.test.d.ts +2 -0
- package/dist/types/src/stages/correction.test.d.ts.map +1 -0
- package/dist/types/src/stages/diarization.d.ts +11 -0
- package/dist/types/src/stages/diarization.d.ts.map +1 -0
- package/dist/types/src/stages/extraction.d.ts +40 -0
- package/dist/types/src/stages/extraction.d.ts.map +1 -0
- package/dist/types/src/stages/extraction.test.d.ts +2 -0
- package/dist/types/src/stages/extraction.test.d.ts.map +1 -0
- package/dist/types/src/stages/index.d.ts +18 -0
- package/dist/types/src/stages/index.d.ts.map +1 -0
- package/dist/types/src/stages/summarization.d.ts +12 -0
- package/dist/types/src/stages/summarization.d.ts.map +1 -0
- package/dist/types/src/stages/translation.d.ts +11 -0
- package/dist/types/src/stages/translation.d.ts.map +1 -0
- package/dist/types/src/testing/conversation-parser.d.ts +26 -0
- package/dist/types/src/testing/conversation-parser.d.ts.map +1 -0
- package/dist/types/src/testing/conversation.test.d.ts +2 -0
- package/dist/types/src/testing/conversation.test.d.ts.map +1 -0
- package/dist/types/src/testing/fixtures.d.ts +6 -0
- package/dist/types/src/testing/fixtures.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +5 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/scripted-source.d.ts +16 -0
- package/dist/types/src/testing/scripted-source.d.ts.map +1 -0
- package/dist/types/src/testing/stream-simulator.d.ts +38 -0
- package/dist/types/src/testing/stream-simulator.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +61 -0
- package/src/PipelineConfig.test.ts +39 -0
- package/src/PipelineConfig.ts +71 -0
- package/src/PipelineRuntime.test.ts +74 -0
- package/src/PipelineRuntime.ts +192 -0
- package/src/Stage.ts +86 -0
- package/src/TranscriptEvent.ts +23 -0
- package/src/asr/audio-recorder.ts +56 -0
- package/src/asr/index.ts +8 -0
- package/src/asr/pipeline.ts +105 -0
- package/src/asr/sentence-buffer.test.ts +53 -0
- package/src/asr/sentence-buffer.ts +88 -0
- package/src/asr/transcriber.test.ts +104 -0
- package/src/asr/transcriber.ts +337 -0
- package/src/asr/util.ts +14 -0
- package/src/dispatch.test.ts +37 -0
- package/src/dispatch.ts +56 -0
- package/src/index.ts +14 -0
- package/src/live.test.ts +63 -0
- package/src/live.ts +56 -0
- package/src/lookup.test.ts +41 -0
- package/src/lookup.ts +60 -0
- package/src/model-routing.ts +25 -0
- package/src/pipeline-integration.test.ts +70 -0
- package/src/stages/correction-llm.test.ts +46 -0
- package/src/stages/correction-llm.ts +40 -0
- package/src/stages/correction.test.ts +26 -0
- package/src/stages/correction.ts +72 -0
- package/src/stages/diarization.ts +24 -0
- package/src/stages/extraction.test.ts +79 -0
- package/src/stages/extraction.ts +151 -0
- package/src/stages/index.ts +44 -0
- package/src/stages/summarization.ts +37 -0
- package/src/stages/translation.ts +26 -0
- package/src/testing/conversation-parser.ts +101 -0
- package/src/testing/conversation.test.ts +53 -0
- package/src/testing/conversation.txt +23 -0
- package/src/testing/fixtures.ts +18 -0
- package/src/testing/index.ts +8 -0
- package/src/testing/scripted-source.ts +35 -0
- package/src/testing/stream-simulator.ts +125 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/Stage.ts", "../../../src/lookup.ts", "../../../src/PipelineConfig.ts", "../../../src/model-routing.ts", "../../../src/PipelineRuntime.ts", "../../../src/live.ts", "../../../src/asr/sentence-buffer.ts", "../../../src/asr/transcriber.ts", "../../../src/asr/util.ts", "../../../src/asr/pipeline.ts", "../../../src/dispatch.ts", "../../../src/stages/index.ts", "../../../src/stages/correction.ts", "../../../src/stages/diarization.ts", "../../../src/stages/extraction.ts", "../../../src/stages/summarization.ts", "../../../src/stages/translation.ts", "../../../src/stages/correction-llm.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport type * as Effect from 'effect/Effect';\n\nimport { DXN, type Ref } from '@dxos/echo';\nimport { type ContentBlock } from '@dxos/types';\n\nimport { type EntityLookup } from './lookup';\n\n/**\n * When a stage's discrete computation fires, relative to the pipeline stream.\n * - `per-block`: on every new transcript block.\n * - `on-silence`: when the speaker pauses (silence edge).\n * - `periodic`: on a timer tick.\n */\nexport type StageTrigger = 'per-block' | 'on-silence' | 'periodic';\n\n/**\n * Policy applied when a stage is triggered while a previous invocation is still in flight.\n * - `latest-wins`: interrupt the in-flight invocation and start a new one over the latest window.\n * - `skip-if-busy`: drop the new trigger and let the in-flight invocation complete.\n */\nexport type StageConcurrency = 'latest-wins' | 'skip-if-busy';\n\n/** Fields of a transcript block that stages may patch. */\nexport type BlockPatch = Partial<{\n corrected: string;\n references: Ref.Ref<any>[];\n candidates: ContentBlock.Candidate[];\n translation: string;\n}>;\n\n/** A patch to a single block, keyed by its index within the window snapshot passed to the stage. */\nexport type BlockUpdate = { index: number } & BlockPatch;\n\n/** A patch to the `Transcript` object itself. */\nexport type TranscriptUpdate = Partial<{\n summary: string;\n summaryUpdatedAt: string;\n resolvedReferents: { surface: string; referent: string; ref?: Ref.Ref<any> }[];\n}>;\n\n/** The result of a stage invocation: a typed description of ECHO mutations. */\nexport type StageWrite = {\n blockUpdates?: BlockUpdate[];\n transcriptUpdate?: TranscriptUpdate;\n};\n\nexport const StageWrite = Object.freeze({\n blocks: (blockUpdates: BlockUpdate[]): StageWrite => ({ blockUpdates }),\n transcript: (transcriptUpdate: TranscriptUpdate): StageWrite => ({ transcriptUpdate }),\n empty: (): StageWrite => ({}),\n});\n\n/** Context supplied to a stage's `run` by the runtime. */\nexport type StageContext = {\n /** Resolves entity references for extraction. Backend-agnostic (full-text, vector, …). */\n readonly lookup?: EntityLookup;\n /** The model resolved for this stage by the runtime (config → stage → preset default). */\n readonly model: DXN.DXN;\n};\n\n/**\n * A pipeline stage: a discrete, repeatedly-invoked transform over a window of the transcript stream.\n *\n * The runtime — not the stage — owns the continuous stream; it builds `input` from a window snapshot\n * (`select`) and invokes `run` once per trigger, enforcing `concurrency` and injecting `model`.\n *\n * LLM-backed stages delegate `run` to an `Operation` (typed I/O, memoized-LLM tests, standalone\n * re-invocation). Pure stages implement `run` directly.\n */\nexport interface Stage<In = unknown, E = unknown> {\n readonly id: string;\n readonly trigger: StageTrigger;\n /** Sliding context size in blocks. Absent → the runtime passes the full current window. */\n readonly window?: { blocks: number };\n readonly concurrency: StageConcurrency;\n /** Default model for the stage; overridden by per-stage config in the runtime. */\n readonly model?: DXN.DXN;\n /** Build the stage input from the current window snapshot. Defaults to `{ window }`. */\n readonly select?: (window: ContentBlock.Transcript[]) => In;\n /** The discrete per-trigger computation. */\n run(input: In, ctx: StageContext): Effect.Effect<StageWrite, E>;\n}\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Database, Filter, Obj, Query, Ref } from '@dxos/echo';\n\n/**\n * A candidate match for a surface noun: the matched object's id, a ref consumers can persist, and a\n * relevance `score` (higher = better) from the search backend's match rank.\n */\nexport type EntityMatch = {\n id: string;\n ref: Ref.Ref<any>;\n score: number;\n};\n\n/**\n * Additional context that narrows a lookup. Grows over time (e.g. the conversation window, an\n * expected role); backends ignore fields they do not support.\n */\nexport type LookupContext = {\n /** Restrict matches to these typenames (e.g. the typename of `Person` / `Organization`). */\n types?: string[];\n};\n\n/**\n * Resolves a surface noun to its candidate matches, ranked best-first, backed by an index. The\n * pipeline depends only on this function — not on ECHO/the database directly — so the backend\n * (full-text, vector, a remote service, …) is an injected concern. Returning candidates (rather than\n * a single match) lets a context-aware resolver disambiguate using the surrounding conversation.\n * Empty when nothing matches.\n */\nexport type EntityLookup = (noun: string, context?: LookupContext) => Promise<EntityMatch[]>;\n\nexport type DatabaseLookupOptions = {\n /** Search backend. Full-text matches proper nouns precisely; vector matches semantically. */\n searchKind?: 'full-text' | 'vector';\n /** Maximum candidates returned per noun. */\n limit?: number;\n};\n\n/** An {@link EntityLookup} backed by an ECHO database query (full-text by default). */\nexport const makeDatabaseLookup =\n (db: Database.Database, { searchKind = 'full-text', limit = 5 }: DatabaseLookupOptions = {}): EntityLookup =>\n async (noun, context) => {\n // `runEntries` exposes each match's relevance rank; `run` would discard it.\n const entries = await db.query(Query.select(Filter.text(noun, { type: searchKind }))).runEntries();\n // Type narrowing is applied here rather than in the query: the executor rejects a text-search\n // filter combined with a type filter (\"query too complex\").\n const types = context?.types;\n return entries\n .flatMap((entry) => {\n if (!entry.result || (types?.length && !types.includes(Obj.getTypename(entry.result) ?? ''))) {\n return [];\n }\n return [{ id: entry.id, ref: Ref.make(entry.result), score: entry.match?.rank ?? 0 }];\n })\n .sort((a, b) => b.score - a.score)\n .slice(0, limit);\n };\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { DXN, Obj, Type } from '@dxos/echo';\n\n/** Cheap, fast default for all stages; same model used by `update-chat-name` / `qualifier`. */\nexport const DEFAULT_STAGE_MODEL: DXN.DXN = DXN.make('com.anthropic.model.claude-haiku-4-5.default');\n\n/** Per-stage configuration entry within a {@link PipelineConfig}. */\nexport const StageConfig = Schema.Struct({\n /** Stage id (matches a registered `Stage.id`). */\n id: Schema.String,\n enabled: Schema.Boolean,\n /** Optional per-stage model override (an NSID name); resolved by the runtime. */\n model: Schema.optional(DXN.NameSchema),\n /** Optional sliding-window override in blocks. Positive integer; bad values fail validation. */\n window: Schema.optional(Schema.Struct({ blocks: Schema.Number.pipe(Schema.int(), Schema.positive()) })),\n});\nexport type StageConfig = Schema.Schema.Type<typeof StageConfig>;\n\n/**\n * Ordered, persisted configuration that drives a {@link PipelineRuntime}: which stages run, in what\n * order, with which model and window. Presets (\"Meeting\", \"Notes\") are seeded instances.\n */\nexport class PipelineConfig extends Type.makeObject<PipelineConfig>(\n DXN.make('org.dxos.type.transcriptionPipelineConfig', '0.1.0'),\n)(\n Schema.Struct({\n name: Schema.String,\n stages: Schema.mutable(Schema.Array(StageConfig)),\n }),\n) {}\n\n/** A plain preset descriptor (used to seed a {@link PipelineConfig} object). */\nexport type PipelinePreset = {\n name: string;\n stages: StageConfig[];\n};\n\n/**\n * Built-in presets. `Meeting` runs the three real stages; `Notes` runs correction (+ extraction)\n * and streams into the editor without a cumulative summary.\n */\nexport const PIPELINE_PRESETS: readonly PipelinePreset[] = Object.freeze([\n {\n name: 'Meeting',\n stages: [\n { id: 'correct', enabled: true },\n { id: 'extract', enabled: true },\n { id: 'summarize', enabled: true },\n ],\n },\n {\n name: 'Notes',\n stages: [\n { id: 'correct', enabled: true },\n { id: 'extract', enabled: false },\n { id: 'summarize', enabled: false },\n ],\n },\n]);\n\nexport const findPreset = (name: string): PipelinePreset | undefined =>\n PIPELINE_PRESETS.find((preset) => preset.name === name);\n\n/** Instantiate a `PipelineConfig` ECHO object from a preset descriptor. */\nexport const makeConfigFromPreset = (preset: PipelinePreset): PipelineConfig =>\n Obj.make(PipelineConfig, { name: preset.name, stages: preset.stages.map((stage) => ({ ...stage })) });\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { DXN } from '@dxos/echo';\n\nimport { DEFAULT_STAGE_MODEL, type StageConfig } from './PipelineConfig';\nimport { type Stage } from './Stage';\n\n/**\n * Resolve the model for a stage invocation. Precedence: per-stage config override → the stage's own\n * default → the preset/pipeline default → the global {@link DEFAULT_STAGE_MODEL}.\n *\n * `StageConfig.model` is a validated NSID name in the schema (its format is checked, but it is not\n * pinned to the current model catalog); it is parsed to a model DXN here for the `AiService` call.\n */\nexport const resolveModel = (\n stageConfig: StageConfig | undefined,\n stage: Stage<any, any>,\n presetDefault?: DXN.DXN,\n): DXN.DXN =>\n (stageConfig?.model ? DXN.tryMake(stageConfig.model) : undefined) ??\n stage.model ??\n presetDefault ??\n DEFAULT_STAGE_MODEL;\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Cause from 'effect/Cause';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport { pipe } from 'effect/Function';\nimport * as Stream from 'effect/Stream';\n\nimport { DXN } from '@dxos/echo';\nimport { log } from '@dxos/log';\nimport { Pipeline, Stage as PipelineStage } from '@dxos/pipeline';\nimport { type ContentBlock } from '@dxos/types';\n\nimport { type EntityLookup } from './lookup';\nimport { resolveModel } from './model-routing';\nimport { type StageConfig } from './PipelineConfig';\nimport { type Stage, type StageContext, type StageWrite } from './Stage';\nimport { type TranscriptEvent } from './TranscriptEvent';\n\n/** Upper bound on retained blocks; bounds memory for long sessions (stages slice their own window). */\nconst MAX_WINDOW = 128;\n\n/** Backpressure lag (in chunks) the broadcast driver may run ahead of the slowest branch. */\nconst BROADCAST_BUFFER = 128;\n\n/**\n * Commits a stage's output to storage. Receives the exact window slice the stage was invoked with,\n * so `BlockUpdate.index` can be resolved against the originating blocks.\n */\nexport type CommitFn = (write: StageWrite, window: readonly ContentBlock.Transcript[]) => Effect.Effect<void>;\n\n/**\n * Outcome reported per stage invocation. The `sliding`/`dropping` overflow model has no fiber-level\n * signal for stale work, so only `committed` and `error` are reported (the previous fiber-based\n * runtime also surfaced `interrupted`/`skipped`).\n */\nexport type StageOutcome = 'committed' | 'error';\n\nexport type TelemetryEvent = {\n readonly stageId: string;\n readonly model: DXN.DXN;\n readonly trigger: TranscriptEvent['kind'];\n readonly durationMs: number;\n readonly outcome: StageOutcome;\n};\n\nexport type RunOptions = {\n /** The continuous transcript event stream (ASR source or a scripted fixture). */\n readonly source: Stream.Stream<TranscriptEvent>;\n /** Ordered stages to run. */\n readonly stages: readonly Stage<any, any>[];\n /** Sink for stage outputs (in-memory capture in tests; ECHO dispatcher in production). */\n readonly commit: CommitFn;\n /** Entity-reference resolver injected into each stage context (backend-agnostic). */\n readonly lookup?: EntityLookup;\n /** Per-stage configuration (enabled / model / window). Absent → stage runs with its defaults. */\n readonly configs?: readonly StageConfig[];\n /** Default model when neither config nor stage specifies one. */\n readonly presetDefault?: DXN.DXN;\n /** Optional telemetry sink (drives the testbench). */\n readonly onTelemetry?: (event: TelemetryEvent) => void;\n};\n\n/** A window slice a stage is invoked over; the commit resolves `BlockUpdate.index` against it. */\ntype Slice = ContentBlock.Transcript[];\n\n/** A stage invocation's output paired with the slice it ran over (needed by {@link CommitFn}). */\ntype Enriched = { readonly write: StageWrite; readonly window: Slice };\n\n/**\n * Private bridge between this module's plain `StageContext` object and `@dxos/pipeline`'s\n * Requirements-based `Stage`. Not part of any public contract: stage authors (see `Stage.ts`) keep\n * receiving `ctx: StageContext` as an explicit parameter; only this module's internal wiring into\n * `@dxos/pipeline` goes through Effect's Context/Layer mechanism.\n */\nclass StageContextService extends Context.Tag('@dxos/pipeline-transcription/StageContextService')<\n StageContextService,\n StageContext\n>() {}\n\nconst triggerMatches = (stage: Stage<any, any>, kind: TranscriptEvent['kind']): boolean =>\n (stage.trigger === 'per-block' && kind === 'block') ||\n (stage.trigger === 'on-silence' && kind === 'silence') ||\n (stage.trigger === 'periodic' && kind === 'tick');\n\nconst triggerKind = (stage: Stage<any, any>): TranscriptEvent['kind'] =>\n stage.trigger === 'per-block' ? 'block' : stage.trigger === 'on-silence' ? 'silence' : 'tick';\n\n/**\n * Per-stage window + trigger, as a `@dxos/pipeline` stage. Maintains this branch's own rolling block\n * window (blocks appended, capped at {@link MAX_WINDOW}) and emits the window slice on events matching\n * the stage's trigger; otherwise it filters the item out, so a non-triggering event never reaches\n * {@link runStage}.\n */\nconst windowTrigger = (\n stage: Stage<any, any>,\n config: StageConfig | undefined,\n): PipelineStage.Stage<TranscriptEvent, Slice> => {\n const blocks = config?.window?.blocks ?? stage.window?.blocks;\n return (input) =>\n input.pipe(\n Stream.mapAccum([] as Slice, (window, event) => {\n const next = event.kind === 'block' ? [...window, event.block].slice(-MAX_WINDOW) : window;\n const slice = triggerMatches(stage, event.kind) ? (blocks ? next.slice(-blocks) : next) : undefined;\n return [next, slice];\n }),\n Stream.filter((slice): slice is Slice => slice !== undefined),\n );\n};\n\n/**\n * Runs the stage over a triggered slice, pairing its write with that slice. Per-stage `overflow`\n * enforces concurrency: `latest-wins → sliding` (a newer slice replaces the queued one), `skip-if-busy\n * → dropping` (new slices dropped while a run is in flight). Neither interrupts the in-flight run —\n * errors are logged + reported and swallowed (emit `undefined` → no commit), as before.\n */\nconst runStage = (\n stage: Stage<any, any>,\n config: StageConfig | undefined,\n presetDefault: DXN.DXN | undefined,\n onTelemetry?: (event: TelemetryEvent) => void,\n): PipelineStage.Stage<Slice, Enriched, never, StageContextService> => {\n const model = resolveModel(config, stage, presetDefault);\n const trigger = triggerKind(stage);\n return PipelineStage.map(\n stage.id,\n (slice: Slice) =>\n Effect.gen(function* () {\n const context = yield* StageContextService;\n const started = yield* Effect.sync(() => Date.now());\n const input = stage.select ? stage.select(slice) : { window: slice };\n const write = yield* stage.run(input, context);\n const durationMs = (yield* Effect.sync(() => Date.now())) - started;\n onTelemetry?.({ stageId: stage.id, model, trigger, durationMs, outcome: 'committed' });\n return { write, window: slice };\n }).pipe(\n Effect.catchAllCause((cause) =>\n Effect.sync(() => {\n log.catch(Cause.squash(cause));\n onTelemetry?.({ stageId: stage.id, model, trigger, durationMs: 0, outcome: 'error' });\n return undefined;\n }),\n ),\n ),\n { overflow: stage.concurrency === 'latest-wins' ? 'sliding' : 'dropping', bufferSize: 1 },\n );\n};\n\n/**\n * Drive each stage's discrete invocations off the event stream. Stages are peers, not a chain: the\n * event stream is broadcast to one `@dxos/pipeline` per enabled stage (each with its own window,\n * trigger, and overflow), all committing to a shared sink. Resolves once the source ends and every\n * branch has drained.\n */\nconst run = (options: RunOptions): Effect.Effect<void> =>\n Effect.scoped(\n Effect.gen(function* () {\n const { source, stages, commit, lookup, configs, presetDefault, onTelemetry } = options;\n const configFor = (id: string): StageConfig | undefined => configs?.find((config) => config.id === id);\n const enabled = stages.filter((stage) => configFor(stage.id)?.enabled ?? true);\n if (enabled.length === 0) {\n return yield* Stream.runDrain(source);\n }\n\n // Isolate commit failures per write: a failed commit must not fail its branch (which, under the\n // unbounded `Effect.forEach`, would interrupt the sibling branches). Log and drop instead.\n const sink: Pipeline.Sink<Enriched> = ({ write, window }) =>\n commit(write, window).pipe(Effect.catchAllCause((cause) => Effect.sync(() => log.catch(Cause.squash(cause)))));\n const branches = yield* source.pipe(Stream.broadcast(enabled.length, BROADCAST_BUFFER));\n\n yield* Effect.forEach(\n branches,\n (branch, index) => {\n const stage = enabled[index];\n const config = configFor(stage.id);\n const context: StageContext = { lookup, model: resolveModel(config, stage, presetDefault) };\n return pipe(\n branch,\n windowTrigger(stage, config),\n runStage(stage, config, presetDefault, onTelemetry),\n Pipeline.run({ sink }),\n Effect.provideService(StageContextService, context),\n );\n },\n { concurrency: 'unbounded', discard: true },\n );\n }),\n );\n\nexport const PipelineRuntime = Object.freeze({ run });\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Queue from 'effect/Queue';\nimport * as Stream from 'effect/Stream';\n\nimport { EffectEx } from '@dxos/effect';\nimport { type ContentBlock } from '@dxos/types';\n\nimport { PipelineRuntime, type RunOptions } from './PipelineRuntime';\nimport { TranscriptEvent } from './TranscriptEvent';\n\n/**\n * Imperative handle to a running pipeline fed by a live ASR source. The source pushes events as they\n * arrive rather than yielding a pre-materialized stream.\n */\nexport type LivePipeline = {\n /** Append a transcript block produced by the ASR source. */\n block: (block: ContentBlock.Transcript) => void;\n /** Report that the speaker has been silent for `sinceMs` (triggers on-silence stages). */\n silence: (sinceMs: number) => void;\n /** Emit a periodic tick (triggers periodic stages). */\n tick: () => void;\n /** Close the source; resolves once the stream ends and all in-flight stages have drained. */\n end: () => Promise<void>;\n};\n\n// A sentinel terminates the source after all queued events are consumed, so the run drains rather\n// than dropping in-flight blocks (Queue.shutdown would discard anything not yet pulled).\nconst END = Symbol('end');\ntype Item = TranscriptEvent | typeof END;\n\n/**\n * Drives {@link PipelineRuntime} from a live ASR source: blocks pushed via the returned handle are\n * enqueued onto the runtime's source stream; `end` closes the stream so the run drains and resolves.\n * This is the single orchestration entry point for live capture — callers supply only the stages,\n * commit sink, and (optional) lookup, mirroring a scripted `PipelineRuntime.run`.\n */\nexport const runLivePipeline = (options: Omit<RunOptions, 'source'>): LivePipeline => {\n const queue = Effect.runSync(Queue.unbounded<Item>());\n const source = Stream.fromQueue(queue).pipe(Stream.takeWhile((item): item is TranscriptEvent => item !== END));\n const done = EffectEx.runPromise(PipelineRuntime.run({ ...options, source }));\n const offer = (item: Item) => Effect.runSync(Queue.offer(queue, item));\n return {\n block: (block) => offer(TranscriptEvent.block(block)),\n silence: (sinceMs) => offer(TranscriptEvent.silence(sinceMs)),\n tick: () => offer(TranscriptEvent.tick()),\n end: async () => {\n offer(END);\n await done;\n Effect.runSync(Queue.shutdown(queue));\n },\n };\n};\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { type ContentBlock } from '@dxos/types';\n\n/**\n * Splits text into complete sentences plus a trailing incomplete remainder.\n *\n * A run of `.`/`!`/`?` followed by whitespace or end-of-string terminates a sentence; an ellipsis\n * (`..`+) is treated as non-terminal so mid-thought pauses keep accumulating. Abbreviations are not\n * special-cased — this is a deterministic heuristic, not a full sentence tokenizer.\n */\nexport const splitSentences = (text: string): { sentences: string[]; rest: string } => {\n const sentences: string[] = [];\n let start = 0;\n for (let index = 0; index < text.length; index++) {\n const char = text[index];\n if (char !== '.' && char !== '!' && char !== '?') {\n continue;\n }\n // Collapse a run of terminators (e.g. \"?!\" or \"...\").\n let end = index;\n while (end + 1 < text.length && (text[end + 1] === '.' || text[end + 1] === '!' || text[end + 1] === '?')) {\n end++;\n }\n const isEllipsis = text.slice(index, end + 1).startsWith('..');\n const next = text[end + 1];\n const atBoundary = next === undefined || /\\s/.test(next);\n if (!isEllipsis && atBoundary) {\n const sentence = text.slice(start, end + 1).trim();\n if (sentence.length > 0) {\n sentences.push(sentence);\n }\n start = end + 1;\n }\n index = end;\n }\n return { sentences, rest: text.slice(start).trim() };\n};\n\n/**\n * Accumulates ASR fragments (which cut mid-sentence at chunk boundaries) and re-emits complete,\n * sentence-aligned transcript blocks. Each emitted block inherits the `started` timestamp of the\n * fragment that began the sentence. `flush` emits whatever remains (e.g. on stop).\n */\nexport class SentenceBuffer {\n #text = '';\n #started?: string;\n\n /** Append a fragment; returns any complete sentences it produced. */\n push(block: ContentBlock.Transcript): ContentBlock.Transcript[] {\n const fragment = block.text.trim();\n if (fragment.length === 0) {\n return [];\n }\n if (this.#text.length === 0) {\n this.#started = block.started;\n }\n this.#text = this.#text.length === 0 ? fragment : `${this.#text} ${fragment}`;\n\n const { sentences, rest } = splitSentences(this.#text);\n if (sentences.length === 0) {\n return [];\n }\n const startedForSentences = this.#started;\n this.#text = rest;\n // The remainder starts a new sentence whose timestamp we don't know yet; cleared until the next push.\n this.#started = rest.length > 0 ? this.#started : undefined;\n return sentences.map((text, index) => ({\n _tag: 'transcript' as const,\n started: index === 0 ? (startedForSentences ?? block.started) : block.started,\n text,\n }));\n }\n\n /** Emit any buffered text as a final sentence. */\n flush(): ContentBlock.Transcript[] {\n const remaining = this.#text.trim();\n this.#text = '';\n const started = this.#started;\n this.#started = undefined;\n if (remaining.length === 0) {\n return [];\n }\n return [{ _tag: 'transcript', started: started ?? new Date(0).toISOString(), text: remaining }];\n }\n}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { WaveFile } from 'wavefile';\n\nimport { DeferredTask, Trigger, synchronized } from '@dxos/async';\nimport { EDGE_SERVICE_DEFAULTS, EdgeServiceName } from '@dxos/config';\nimport { type Context, LifecycleState, Resource } from '@dxos/context';\nimport { log } from '@dxos/log';\nimport { trace } from '@dxos/tracing';\nimport { type ContentBlock } from '@dxos/types';\n\nimport { type AudioChunk, type AudioRecorder } from './audio-recorder';\nimport { mergeFloat64Arrays } from './util';\n\nexport type WhisperWord = {\n word: string;\n\n /**\n * Time in seconds from the start of the audio.\n */\n start: number;\n\n /**\n * Time in seconds from the start of the audio.\n */\n end: number;\n};\n\nexport type WhisperSegment = {\n text: string;\n\n /**\n * Time in seconds from the start of the audio.\n */\n start: number;\n\n /**\n * Time in seconds from the start of the audio.\n */\n end: number;\n\n /**\n * Probability of no speech in the segment.\n */\n no_speech_prob: number;\n\n words: WhisperWord[];\n};\n\nexport type TranscribeConfig = {\n /**\n * Number of chunks to transcribe automatically after.\n */\n transcribeAfterChunksAmount: number;\n\n /**\n * Number of chunks to save before the user starts speaking.\n * This is needed to catch the beginning of the user's speech.\n */\n prefixBufferChunksAmount: number;\n\n /**\n * Override the transcription endpoint base URL.\n * Defaults to the DXOS calls service.\n */\n endpoint?: string;\n};\n\n/**\n * Function that converts a base64-encoded WAV payload into Whisper segments.\n * Allows callers to swap in alternative providers or mock the transport.\n */\nexport type TranscribeFn = (audio: string) => Promise<WhisperSegment[]>;\n\nexport type TranscriberProps = {\n config: TranscribeConfig;\n recorder: AudioRecorder;\n /**\n * Optional override of the transcription transport. When provided, supersedes `config.endpoint`.\n */\n transcribe?: TranscribeFn;\n /**\n * Callback to handle the transcribed segments, after all segment transformers are applied.\n * @param segments - The transcribed segments.\n */\n onSegments: (segments: ContentBlock.Transcript[]) => Promise<void>;\n};\n\n/**\n * Handles transcription of audio chunks.\n * If user is not speaking, the last `minChunksAmount` chunks are saved and transcribed.\n * If user is speaking, the chunks are added to the buffer until the user is done talking.\n */\nexport class Transcriber extends Resource {\n private _audioChunks: AudioChunk[] = [];\n private _lastTimestamp = 0;\n\n private readonly _openTrigger = new Trigger({ autoReset: true });\n\n private readonly _config: TranscribeConfig;\n private readonly _recorder: AudioRecorder;\n private readonly _onSegments: TranscriberProps['onSegments'];\n private readonly _transcribeFn?: TranscribeFn;\n\n private _recording = false;\n private _transcribeTask?: DeferredTask = undefined;\n /** Aborts the in-flight transcription request (e.g. when the user cancels the drain). */\n private _transcribeAbort?: AbortController = undefined;\n\n constructor({ config, recorder, onSegments, transcribe }: TranscriberProps) {\n super();\n this._config = config;\n this._recorder = recorder;\n this._onSegments = onSegments;\n this._transcribeFn = transcribe;\n }\n\n protected override async _open(ctx: Context): Promise<void> {\n log.info('opening');\n this._recorder.setOnChunk((chunk) => this._saveAudioChunk(chunk));\n await this._recorder.start();\n this._transcribeTask = new DeferredTask(ctx, async () => this._transcribe());\n this._openTrigger.wake();\n }\n\n protected override async _close(): Promise<void> {\n log.info('closing');\n this._recording = false;\n this._transcribeTask = undefined;\n this._transcribeAbort?.abort();\n await this._recorder.stop();\n }\n\n /** Abort the in-flight transcription request (e.g. user cancelled the drain). */\n abort(): void {\n this._transcribeAbort?.abort();\n }\n\n startChunksRecording(): void {\n log.info('starting');\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n\n this._recording = true;\n }\n\n stopChunksRecording(): void {\n if (this._lifecycleState !== LifecycleState.OPEN || !this._recording) {\n return;\n }\n\n this._recording = false;\n this._transcribeTask?.schedule();\n log.info('stopped');\n }\n\n /**\n * Stop recording and transcribe any buffered audio, resolving once the final segments have been\n * delivered via `onSegments`. Used to drain the pipeline when recording stops so the tail of speech\n * (and its downstream enrichment) is not lost.\n */\n async flush(): Promise<void> {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n\n this._recording = false;\n await this._transcribe();\n }\n\n private _saveAudioChunk(chunk: AudioChunk): void {\n log('saving audio chunk', { chunk });\n this._audioChunks.push(chunk);\n\n // Clean the buffer if the user is not speaking and the transcription task is not scheduled.\n if (\n !this._recording &&\n (!this._transcribeTask || !this._transcribeTask.scheduled) &&\n this._audioChunks.length >= this._config.prefixBufferChunksAmount\n ) {\n this._audioChunks = this._dropOldChunks();\n } else if (this._audioChunks.length >= this._config.transcribeAfterChunksAmount && this._recording) {\n this._transcribeTask?.schedule();\n }\n }\n\n // Serialized so a threshold-scheduled run and a flush()/deferred run cannot read the same buffer\n // concurrently and duplicate or drop tail segments.\n @synchronized\n private async _transcribe(): Promise<void> {\n log('transcribing', { chunks: this._audioChunks.length });\n const chunks = this._audioChunks;\n this._audioChunks = this._dropOldChunks();\n if (chunks.length === 0) {\n return;\n }\n\n const audio = await this._mergeAudioChunks(chunks);\n const segments = await this._fetchTranscription(audio);\n if (!Array.isArray(segments) || segments.length === 0) {\n return;\n }\n\n const alignedSegments = this._alignSegments(segments, chunks);\n if (alignedSegments.length > 0) {\n await this._onSegments(alignedSegments);\n }\n }\n\n private _dropOldChunks(): AudioChunk[] {\n return this._config.prefixBufferChunksAmount > 0\n ? this._audioChunks.slice(-this._config.prefixBufferChunksAmount)\n : [];\n }\n\n @trace.span({ showInBrowserTimeline: true })\n private async _mergeAudioChunks(chunks: AudioChunk[]): Promise<string> {\n const file = new WaveFile();\n const wavConfig = this._recorder.wavConfig;\n\n file.fromScratch(\n wavConfig.channels,\n wavConfig.sampleRate,\n wavConfig.bitDepthCode,\n mergeFloat64Arrays(chunks.map(({ data }) => data)),\n );\n\n return file.toBase64();\n }\n\n @trace.span({ showInBrowserTimeline: true })\n private async _fetchTranscription(audio: string): Promise<WhisperSegment[]> {\n if (audio.length === 0) {\n throw new Error('No audio to send for transcribing');\n }\n\n let segments: unknown;\n if (this._transcribeFn) {\n segments = await this._transcribeFn(audio);\n } else {\n // TODO(burdon): Create separate endpoint?\n const endpoint = this._config.endpoint ?? EDGE_SERVICE_DEFAULTS[EdgeServiceName.Transcription];\n this._transcribeAbort = new AbortController();\n let response: Response;\n try {\n response = await fetch(`${endpoint}/transcribe`, {\n method: 'POST',\n body: JSON.stringify({ audio }),\n headers: {\n 'Content-Type': 'application/json',\n },\n signal: this._transcribeAbort.signal,\n });\n } catch (err) {\n // Aborting (user cancelled the drain) is a clean stop, not a failed transcription cycle.\n if (err instanceof DOMException && err.name === 'AbortError') {\n return [];\n }\n throw err;\n } finally {\n this._transcribeAbort = undefined;\n }\n\n if (!response.ok) {\n throw new Error(`Transcription failed: ${response.statusText}`);\n }\n\n ({ segments } = (await response.json()) as { segments?: unknown });\n }\n\n if (!Array.isArray(segments)) {\n throw new Error('Transcription response payload is invalid');\n }\n\n log.info('transcription response', { segments: segments.length });\n return segments as WhisperSegment[];\n }\n\n private _alignSegments(segments: WhisperSegment[], originalChunks: AudioChunk[]): ContentBlock.Transcript[] {\n const result = alignWhisperSegments(segments, originalChunks, this._lastTimestamp);\n if (result.lastTimestamp !== undefined) {\n this._lastTimestamp = result.lastTimestamp;\n }\n\n return result.transcripts;\n }\n}\n\n/**\n * Pure helper that filters and absolute-timestamps Whisper segments against a chunk timeline.\n * Exported for testing.\n *\n * @param segments - Raw segments returned by the Whisper service for `originalChunks`.\n * @param originalChunks - Chunks fed into the transcription request (used for the zero timestamp).\n * @param lastTimestamp - Most recent absolute timestamp already emitted; segments whose end\n * falls strictly before this point are deduped out, as are individual words whose start does.\n */\nexport const alignWhisperSegments = (\n segments: WhisperSegment[],\n originalChunks: AudioChunk[],\n lastTimestamp: number,\n): { transcripts: ContentBlock.Transcript[]; lastTimestamp?: number } => {\n if (originalChunks.length === 0) {\n return { transcripts: [] };\n }\n\n const zeroTimestamp = originalChunks[0].timestamp;\n\n const filteredSegments = segments\n .filter((segment) => zeroTimestamp + segment.end * 1_000 >= lastTimestamp)\n .map((segment) => {\n const words = segment.words.filter((word) => zeroTimestamp + word.start * 1_000 >= lastTimestamp);\n return {\n ...segment,\n words,\n text: words.map((word) => word.word).join(''),\n start: words.at(0)?.start ?? segment.end,\n };\n })\n .filter((segment) => segment.words.length > 0);\n\n if (filteredSegments.length === 0) {\n return { transcripts: [] };\n }\n\n return {\n lastTimestamp: zeroTimestamp + filteredSegments.at(-1)!.end * 1_000,\n transcripts: filteredSegments.map((segment) => ({\n _tag: 'transcript',\n started: new Date(zeroTimestamp + segment.start * 1_000).toISOString(),\n text: segment.text.trim(),\n })),\n };\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nexport const mergeFloat64Arrays = (arrays: Float64Array[]) => {\n const newArray = new Float64Array(arrays.reduce((acc, array) => array.length + acc, 0));\n let offset = 0;\n for (const array of arrays) {\n newArray.set(array, offset);\n offset += array.length;\n }\n\n return newArray;\n};\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { type ContentBlock } from '@dxos/types';\n\nimport { type LivePipeline, runLivePipeline } from '../live';\nimport { type RunOptions } from '../PipelineRuntime';\nimport { type AudioRecorder } from './audio-recorder';\nimport { SentenceBuffer } from './sentence-buffer';\nimport { type TranscribeConfig, type TranscribeFn, Transcriber } from './transcriber';\n\nexport type AsrPipelineOptions = Omit<RunOptions, 'source'> & {\n /** Audio source — browser `MediaStreamRecorder` or any `AudioRecorder` implementation. */\n recorder: AudioRecorder;\n /** Optional ASR transport override (default: `fetch` to the edge transcription service). */\n transcribe?: TranscribeFn;\n /** Transcriber chunking configuration. */\n config: TranscribeConfig;\n /**\n * Re-segment the ASR output into complete sentences before it enters the pipeline, merging\n * fragments that the transcriber cut mid-sentence at chunk boundaries. @default false\n */\n segmentSentences?: boolean;\n /** Optional raw-segment hook invoked before each block enters the pipeline (e.g. live display). */\n onSegment?: (block: ContentBlock.Transcript) => void;\n /** Silence (ms) reported on `end` so on-silence stages fire over the final window. */\n drainSilenceMs?: number;\n};\n\n/** Imperative handle to a running ASR → pipeline session. */\nexport type AsrPipeline = {\n /** Open the recorder + transcriber. */\n open: () => Promise<void>;\n /** Begin capturing audio for transcription. */\n start: () => void;\n /** Stop capturing (buffered audio is still flushed by `end`). */\n stop: () => void;\n /** Abort the in-flight transcription request. */\n abort: () => void;\n /** Flush buffered audio, signal silence, and drain the pipeline. */\n end: () => Promise<void>;\n};\n\n/**\n * The single end-to-end wiring: an ASR source ({@link Transcriber}) feeding the live orchestration\n * engine ({@link runLivePipeline}). Every consumer (editor driver, message-list recording, stories)\n * differs only by recorder, stages, and commit sink — this is the one place audio → text → stages →\n * sink is assembled.\n */\nexport const runAsrPipeline = ({\n recorder,\n transcribe,\n config,\n segmentSentences = false,\n onSegment,\n drainSilenceMs = 5_000,\n ...runOptions\n}: AsrPipelineOptions): AsrPipeline => {\n const live: LivePipeline = runLivePipeline(runOptions);\n // Optionally merge mid-sentence ASR fragments into complete sentences before the pipeline sees them.\n const sentences = segmentSentences ? new SentenceBuffer() : undefined;\n const emit = (block: ContentBlock.Transcript) => {\n onSegment?.(block);\n live.block(block);\n };\n const handle = (blocks: ContentBlock.Transcript[]) => {\n for (const block of blocks) {\n if (sentences) {\n for (const sentence of sentences.push(block)) {\n emit(sentence);\n }\n } else {\n emit(block);\n }\n }\n };\n const transcriber = new Transcriber({\n config,\n recorder,\n transcribe,\n onSegments: async (blocks: ContentBlock.Transcript[]) => handle(blocks),\n });\n\n return {\n open: async () => {\n await transcriber.open();\n },\n start: () => transcriber.startChunksRecording(),\n stop: () => transcriber.stopChunksRecording(),\n abort: () => transcriber.abort(),\n end: async () => {\n await transcriber.flush();\n // Emit any sentence still buffered after the final flush.\n if (sentences) {\n for (const sentence of sentences.flush()) {\n emit(sentence);\n }\n }\n live.silence(drainSilenceMs);\n await live.end();\n await transcriber.close();\n },\n };\n};\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Obj } from '@dxos/echo';\nimport { type ContentBlock, type Transcript } from '@dxos/types';\n\nimport { type CommitFn } from './PipelineRuntime';\nimport { type StageWrite } from './Stage';\n\n/**\n * In-memory commit sink: records every {@link StageWrite} for assertions and testbench rendering.\n */\nexport type CaptureCommit = {\n readonly commit: CommitFn;\n readonly writes: StageWrite[];\n};\n\nexport const captureCommit = (): CaptureCommit => {\n const writes: StageWrite[] = [];\n const commit: CommitFn = (write) =>\n Effect.sync(() => {\n writes.push(write);\n });\n return { commit, writes };\n};\n\n/**\n * ECHO commit: applies a stage's output to live objects. Block patches are applied to the block\n * objects in the window slice the stage was invoked with (the runtime passes that slice); the\n * transcript patch is applied to the `Transcript` object. Mutating a live ECHO object propagates\n * via reactivity; a containing `Obj.update` transaction (when present) batches the writes.\n */\nexport const makeEchoCommit =\n (transcript: Transcript.Transcript): CommitFn =>\n (write, window) =>\n Effect.sync(() => {\n for (const update of write.blockUpdates ?? []) {\n const block: ContentBlock.Transcript | undefined = window[update.index];\n if (!block) {\n continue;\n }\n const { index: _index, ...patch } = update;\n // Live ECHO objects must be mutated inside Obj.update; plain blocks (testbench) assign directly.\n if (Obj.isObject(block)) {\n Obj.update(block, (block) => Object.assign(block, patch));\n } else {\n Object.assign(block, patch);\n }\n }\n if (write.transcriptUpdate) {\n Obj.update(transcript, (transcript) => Object.assign(transcript, write.transcriptUpdate));\n }\n });\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { log } from '@dxos/log';\n\nimport { type Stage } from '../Stage';\nimport { makeCorrectionStage } from './correction';\nimport { makeDiarizationStage } from './diarization';\nimport { makeExtractionStage } from './extraction';\nimport { makeSummarizationStage } from './summarization';\nimport { makeTranslationStage } from './translation';\n\nexport * from './correction';\nexport * from './correction-llm';\nexport * from './extraction';\nexport * from './summarization';\nexport * from './translation';\nexport * from './diarization';\n\n/**\n * The default registry of stage factories keyed by stage id. Consumers build a stage list for a\n * `PipelineConfig` by selecting enabled ids in config order.\n */\nexport const STAGE_FACTORIES: Readonly<Record<string, () => Stage<any, any>>> = Object.freeze({\n correct: makeCorrectionStage,\n extract: makeExtractionStage,\n summarize: makeSummarizationStage,\n translate: makeTranslationStage,\n diarize: makeDiarizationStage,\n});\n\n/** Build the ordered, enabled stage list for a set of stage configs. */\nexport const buildStages = (configs: readonly { id: string; enabled: boolean }[]): Stage<any, any>[] => {\n // Surface unknown ids (stale / mistyped persisted config) rather than silently dropping them, so a\n // config migration miss is visible at setup instead of leaving the runtime quietly under-configured.\n const unknown = configs.filter((config) => config.enabled && !STAGE_FACTORIES[config.id]).map((config) => config.id);\n if (unknown.length > 0) {\n log.warn('ignoring unknown pipeline stage ids', { unknown, known: Object.keys(STAGE_FACTORIES) });\n }\n return configs\n .filter((config) => config.enabled && STAGE_FACTORIES[config.id])\n .map((config) => STAGE_FACTORIES[config.id]());\n};\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { type ContentBlock } from '@dxos/types';\n\nimport { DEFAULT_STAGE_MODEL } from '../PipelineConfig';\nimport { type Stage, StageWrite } from '../Stage';\n\nexport type CorrectionInput = { window: ContentBlock.Transcript[] };\n\n/**\n * Corrects a window of transcript blocks, returning a `{ index, corrected }` patch per block it\n * changes. The deterministic default is used unless an LLM-backed corrector is injected (see\n * `correctWithLanguageModel`); the consumer binds the AI service and adapts it to this Promise shape.\n */\nexport type CorrectFn = (\n blocks: readonly ContentBlock.Transcript[],\n) => Promise<ReadonlyArray<{ index: number; corrected: string }>>;\n\nexport type CorrectionOptions = {\n /** Inject an LLM-backed corrector; omit for the deterministic per-block correction. */\n correct?: CorrectFn;\n};\n\n/**\n * Deterministic correction: trim, capitalize the first letter, ensure terminal punctuation.\n * The LLM seam (see `run`) replaces this with cross-batch repair over the window.\n */\nexport const correctText = (text: string): string => {\n const trimmed = text.trim();\n if (trimmed.length === 0) {\n return trimmed;\n }\n const capitalized = trimmed.charAt(0).toUpperCase() + trimmed.slice(1);\n if (/[.!?]$/.test(capitalized)) {\n return capitalized;\n }\n // Replace a trailing non-terminal mark (comma/semicolon/colon) with the period rather than\n // appending — a Whisper fragment like \"Years,\" would otherwise become \"Years,.\".\n return `${capitalized.replace(/[,;:]+$/, '')}.`;\n};\n\n/**\n * Stage ①: clean up the most recent transcript block (punctuation, capitalization).\n * Windowed for cross-batch context; emits a correction for the newest block.\n */\nexport const makeCorrectionStage = ({ correct }: CorrectionOptions = {}): Stage<CorrectionInput> => ({\n id: 'correct',\n trigger: 'per-block',\n window: { blocks: 8 },\n concurrency: 'latest-wins',\n model: DEFAULT_STAGE_MODEL,\n run: ({ window }) =>\n correct\n ? // LLM seam: the injected corrector repairs the window (cross-batch word/punctuation fixes).\n Effect.promise(() => correct(window)).pipe(\n Effect.map((updates) => (updates.length > 0 ? StageWrite.blocks([...updates]) : StageWrite.empty())),\n )\n : Effect.sync(() => {\n // Deterministic fallback: correct every not-yet-corrected block in the window. Robust under\n // latest-wins — if earlier invocations were interrupted, the surviving run still covers their\n // blocks; already-corrected blocks are skipped once the write is applied back (idempotent).\n const updates = window\n .map((block, index) => ({ block, index }))\n .filter(({ block }) => block.corrected === undefined)\n .map(({ block, index }) => ({ index, corrected: correctText(block.text) }));\n return updates.length > 0 ? StageWrite.blocks(updates) : StageWrite.empty();\n }),\n});\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { type ContentBlock } from '@dxos/types';\n\nimport { type Stage, StageWrite } from '../Stage';\n\nexport type DiarizationInput = { window: ContentBlock.Transcript[] };\n\n/**\n * Stage ◆ (interface only / deferred): label the speaker of the newest block.\n * Conforms to the `Stage` contract and is inert until a diarization backend is wired.\n */\nexport const makeDiarizationStage = (): Stage<DiarizationInput> => ({\n id: 'diarize',\n trigger: 'per-block',\n window: { blocks: 1 },\n concurrency: 'latest-wins',\n // TODO: implement diarization (assign speaker identity to the block).\n run: () => Effect.succeed(StageWrite.empty()),\n});\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { insertReferences } from '@dxos/assistant/extraction';\nimport { type Ref } from '@dxos/echo';\nimport { type ContentBlock } from '@dxos/types';\n\nimport { type EntityLookup } from '../lookup';\nimport { DEFAULT_STAGE_MODEL } from '../PipelineConfig';\nimport { type BlockUpdate, type Stage, StageWrite } from '../Stage';\n\nexport type ExtractionInput = { window: ContentBlock.Transcript[] };\n\nconst STOP_WORDS = new Set([\n 'I',\n 'Yes',\n 'No',\n 'But',\n 'And',\n 'Or',\n 'So',\n 'They',\n 'We',\n 'He',\n 'She',\n 'It',\n 'The',\n 'A',\n 'An',\n 'Is',\n 'Are',\n 'Was',\n 'Were',\n 'Be',\n 'Been',\n 'This',\n 'That',\n]);\n\n/**\n * Deterministic proper-noun heuristic: capitalized word runs, minus sentence-initial stop-words.\n * The LLM seam (see `run`) replaces this with model-driven NER.\n */\nexport const extractProperNouns = (text: string): string[] => {\n const matches = text.match(/\\b[A-Z][a-zA-Z]+(?:\\s+[A-Z][a-zA-Z]+)*\\b/g) ?? [];\n return Array.from(new Set(matches.filter((word) => !STOP_WORDS.has(word))));\n};\n\n/** Marker that a block's text already carries inline echo links, so extraction can skip it. */\nexport const isLinked = (text: string): boolean => text.includes('](echo:');\n\n/** Result of resolving a block's proper nouns against the {@link EntityLookup}. */\nexport type ExtractedEntities = {\n references: Ref.Ref<any>[];\n quotes: { quote: string; id: string }[];\n candidates: ContentBlock.Candidate[];\n};\n\n/** Resolve a block's proper nouns: matched → references/quotes, unmatched → candidates. */\nexport const resolveEntities = async (text: string, lookup?: EntityLookup): Promise<ExtractedEntities> => {\n const nouns = extractProperNouns(text);\n const references: Ref.Ref<any>[] = [];\n const quotes: { quote: string; id: string }[] = [];\n const matched = new Set<string>();\n if (lookup) {\n for (const noun of nouns) {\n // TODO(LLM seam): replace heuristic nouns with model NER, and disambiguate tied candidates\n // against the conversation window (the stage's `window` + `resolvedReferents`) instead of\n // leaving them as candidates. The lookup backend stays injected.\n const candidates = await lookup(noun); // ranked best-first.\n // Auto-link only a clear winner: the top candidate must strictly out-rank the runner-up. A tie\n // at the top is genuine ambiguity, left for the context-aware resolver / the user — so we never\n // link the wrong object on a guess. (Text search returns weak spurious matches too, so counting\n // candidates is not a reliable ambiguity signal; the rank gap is.)\n const unambiguous =\n candidates.length === 1 || (candidates.length > 1 && candidates[0].score > candidates[1].score);\n if (candidates.length > 0 && unambiguous) {\n references.push(candidates[0].ref);\n quotes.push({ quote: noun, id: candidates[0].id });\n matched.add(noun.toLowerCase());\n }\n }\n }\n const candidates: ContentBlock.Candidate[] = nouns\n .filter((noun) => !matched.has(noun.toLowerCase()))\n .map((noun) => {\n const start = Math.max(0, text.indexOf(noun));\n return { text: noun, kind: 'proper-noun' as const, start, end: start + noun.length };\n });\n return { references, quotes, candidates };\n};\n\n/**\n * Rewrite text with inline `[noun](echo:/<id>)` links for entities matched by `lookup`, so markdown\n * consumers decorate them as dx-anchors. Reused by the live recording driver's post-process seam.\n */\nexport const linkEntities = async (text: string, lookup: EntityLookup): Promise<string> => {\n if (isLinked(text)) {\n return text;\n }\n const { quotes } = await resolveEntities(text, lookup);\n return quotes.length > 0 ? insertReferences(text, { references: quotes }) : text;\n};\n\n/**\n * Stage ②: surface proper nouns across the window, link those that match objects (via the injected\n * {@link EntityLookup}), and report the rest as candidates the user can act on.\n *\n * Processes every not-yet-linked block in the window (not just the newest). Under `latest-wins`\n * with a fast stream, earlier per-block invocations are interrupted, so the surviving invocation\n * must cover the whole window — otherwise blocks behind the head never get extracted.\n */\nexport const makeExtractionStage = (): Stage<ExtractionInput> => ({\n id: 'extract',\n trigger: 'per-block',\n window: { blocks: 8 },\n concurrency: 'latest-wins',\n model: DEFAULT_STAGE_MODEL,\n run: ({ window }, ctx) =>\n Effect.gen(function* () {\n const updates: BlockUpdate[] = [];\n for (let index = 0; index < window.length; index++) {\n const block = window[index];\n const text = block.corrected ?? block.text;\n // Idempotent across windowed re-invocations: already-linked blocks need no further work.\n if (isLinked(text)) {\n continue;\n }\n const { references, quotes, candidates } = yield* Effect.promise(() => resolveEntities(text, ctx.lookup));\n\n const update: BlockUpdate = { index };\n if (references.length > 0) {\n update.references = references;\n }\n if (candidates.length > 0) {\n update.candidates = candidates;\n }\n // Inline links so markdown consumers render dx-anchors; structured references stay for others.\n if (quotes.length > 0) {\n update.corrected = insertReferences(text, { references: quotes });\n }\n if (update.references || update.candidates || update.corrected) {\n updates.push(update);\n }\n }\n return updates.length > 0 ? StageWrite.blocks(updates) : StageWrite.empty();\n }),\n});\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { type ContentBlock } from '@dxos/types';\n\nimport { DEFAULT_STAGE_MODEL } from '../PipelineConfig';\nimport { type Stage, StageWrite } from '../Stage';\n\nexport type SummarizationInput = { window: ContentBlock.Transcript[] };\n\n/**\n * Stage ④: maintain a cumulative summary. Fires on the silence edge, skips if a summary is already\n * in flight. The deterministic implementation concatenates corrected utterances; the LLM seam\n * (see `run`) replaces it with a cumulative model summary plus referent resolution.\n */\nexport const makeSummarizationStage = (): Stage<SummarizationInput> => ({\n id: 'summarize',\n trigger: 'on-silence',\n concurrency: 'skip-if-busy',\n model: DEFAULT_STAGE_MODEL,\n run: ({ window }) =>\n Effect.sync(() => {\n const utterances = window.map((block) => (block.corrected ?? block.text).trim()).filter(Boolean);\n if (utterances.length === 0) {\n return StageWrite.empty();\n }\n // TODO(LLM seam): replace with a cumulative LLM summary that resolves deictic referents\n // (\"I\" → speaker, \"there\" → prior entity) and writes `resolvedReferents`.\n return StageWrite.transcript({\n summary: utterances.join(' '),\n summaryUpdatedAt: new Date().toISOString(),\n });\n }),\n});\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { type ContentBlock } from '@dxos/types';\n\nimport { DEFAULT_STAGE_MODEL } from '../PipelineConfig';\nimport { type Stage, StageWrite } from '../Stage';\n\nexport type TranslationInput = { window: ContentBlock.Transcript[] };\n\n/**\n * Stage ③ (interface only / deferred): translate the newest block into `targetLanguage`.\n * Conforms to the `Stage` contract and is inert until a translation backend is wired.\n */\nexport const makeTranslationStage = (_targetLanguage = 'en'): Stage<TranslationInput> => ({\n id: 'translate',\n trigger: 'per-block',\n window: { blocks: 1 },\n concurrency: 'latest-wins',\n model: DEFAULT_STAGE_MODEL,\n // TODO: implement translation (per-block; writes block.translation via a model call).\n run: () => Effect.succeed(StageWrite.empty()),\n});\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as LanguageModel from '@effect/ai/LanguageModel';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\nimport * as Schema from 'effect/Schema';\n\nimport { AiService } from '@dxos/ai';\nimport { DXN } from '@dxos/echo';\nimport { type ContentBlock } from '@dxos/types';\n\nimport { DEFAULT_STAGE_MODEL } from '../PipelineConfig';\n\nconst CorrectionPayload = Schema.Struct({\n blocks: Schema.Array(Schema.Struct({ index: Schema.Number, corrected: Schema.String })),\n});\n\nconst PROMPT = `You repair raw speech-to-text fragments. For each numbered fragment, return a cleaned version: fix capitalization and terminal punctuation, join words split across fragment boundaries, and drop filler/garbage tokens — without changing the meaning. Return exactly one entry per input fragment, preserving its index.`;\n\n/**\n * LLM-backed correction over a window of transcript blocks (the {@link makeCorrectionStage} seam).\n * Returns an Effect requiring the {@link AiService} — the consumer provides its model layer and adapts\n * the Effect to the stage's Promise-shaped `CorrectFn` (e.g. `EffectEx.runPromise(... .pipe(Effect.provide(layer)))`).\n */\nexport const correctWithLanguageModel = (\n blocks: readonly ContentBlock.Transcript[],\n model: DXN.DXN = DEFAULT_STAGE_MODEL,\n): Effect.Effect<ReadonlyArray<{ index: number; corrected: string }>, unknown, AiService.AiService> =>\n Effect.gen(function* () {\n const input = blocks.map((block, index) => `${index}: ${block.corrected ?? block.text}`).join('\\n');\n const response = yield* LanguageModel.generateObject({\n schema: CorrectionPayload,\n prompt: `${PROMPT}\\n\\n${input}`,\n });\n return response.value.blocks.map((block) => ({ index: block.index, corrected: block.corrected }));\n // Model-layer construction failure is a fatal wiring fault (defect); transient LLM failures stay\n // recoverable so callers can retry.\n }).pipe(Effect.provide(AiService.model(DXN.getName(model)).pipe(Layer.orDie)));\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["StageWrite", "Object", "freeze", "blocks", "blockUpdates", "transcript", "transcriptUpdate", "empty", "Filter", "Obj", "Query", "Ref", "makeDatabaseLookup", "db", "searchKind", "limit", "noun", "context", "entries", "query", "select", "text", "type", "runEntries", "types", "flatMap", "entry", "result", "length", "includes", "getTypename", "id", "ref", "make", "score", "match", "rank", "sort", "a", "b", "slice", "Schema", "DXN", "Obj", "Type", "DEFAULT_STAGE_MODEL", "make", "StageConfig", "Struct", "id", "String", "enabled", "Boolean", "model", "optional", "NameSchema", "window", "blocks", "Number", "pipe", "int", "positive", "PipelineConfig", "makeObject", "name", "stages", "mutable", "Array", "PIPELINE_PRESETS", "Object", "freeze", "findPreset", "find", "preset", "makeConfigFromPreset", "map", "stage", "DXN", "resolveModel", "stageConfig", "stage", "presetDefault", "model", "DXN", "tryMake", "undefined", "DEFAULT_STAGE_MODEL", "Cause", "Context", "Effect", "pipe", "Stream", "log", "Pipeline", "Stage", "PipelineStage", "triggerMatches", "trigger", "pipe", "Stream", "mapAccum", "next", "event", "window", "block", "slice", "triggerKind", "stage", "PipelineStage", "context", "StageContextService", "started", "Effect", "Date", "input", "select", "write", "onTelemetry", "stageId", "id", "model", "durationMs", "outcome", "catchAllCause", "undefined", "overflow", "bufferSize", "configFor", "configs", "config", "enabled", "stages", "filter", "runDrain", "source", "forEach", "branches", "branch", "index", "lookup", "resolveModel", "windowTrigger", "runStage", "provideService", "concurrency", "run", "Effect", "Queue", "Stream", "EffectEx", "END", "Symbol", "runLivePipeline", "options", "queue", "runSync", "unbounded", "source", "fromQueue", "pipe", "takeWhile", "item", "done", "EffectEx", "runPromise", "PipelineRuntime", "run", "offer", "block", "TranscriptEvent", "silence", "sinceMs", "tick", "end", "Effect", "shutdown", "splitSentences", "text", "sentences", "start", "index", "length", "char", "end", "isEllipsis", "slice", "startsWith", "next", "atBoundary", "undefined", "test", "sentence", "trim", "push", "rest", "SentenceBuffer", "block", "fragment", "started", "startedForSentences", "map", "_tag", "flush", "remaining", "Date", "toISOString", "DeferredTask", "Trigger", "EDGE_SERVICE_DEFAULTS", "EdgeServiceName", "LifecycleState", "Resource", "log", "trace", "mergeFloat64Arrays", "mergeFloat64Arrays", "arrays", "newArray", "Float64Array", "reduce", "acc", "array", "length", "offset", "set", "_audioChunks", "_lastTimestamp", "_openTrigger", "_config", "_recorder", "_onSegments", "_transcribeFn", "_recording", "_transcribeTask", "log", "setOnChunk", "chunk", "_saveAudioChunk", "DeferredTask", "__dxlog_file", "_transcribeAbort", "abort", "stop", "startChunksRecording", "_lifecycleState", "LifecycleState", "stopChunksRecording", "info", "_transcribe", "_dropOldChunks", "length", "schedule", "chunks", "segments", "_fetchTranscription", "audio", "Array", "isArray", "alignedSegments", "WaveFile", "wavConfig", "file", "fromScratch", "channels", "toBase64", "AbortController", "response", "method", "body", "JSON", "headers", "signal", "Error", "_alignSegments", "result", "alignWhisperSegments", "lastTimestamp", "undefined", "span", "showInBrowserTimeline", "originalChunks", "transcripts", "filteredSegments", "filter", "segment", "word", "zeroTimestamp", "start", "words", "text", "map", "_tag", "started", "runAsrPipeline", "recorder", "transcribe", "config", "segmentSentences", "onSegment", "drainSilenceMs", "runOptions", "live", "runLivePipeline", "sentences", "SentenceBuffer", "undefined", "emit", "block", "handle", "blocks", "sentence", "push", "transcriber", "Transcriber", "onSegments", "open", "start", "startChunksRecording", "stop", "stopChunksRecording", "abort", "end", "flush", "silence", "close", "Effect", "Obj", "captureCommit", "writes", "commit", "write", "sync", "push", "makeEchoCommit", "transcript", "window", "update", "blockUpdates", "block", "index", "_index", "patch", "isObject", "Object", "assign", "transcriptUpdate", "log", "Effect", "correctText", "text", "trimmed", "trim", "length", "capitalized", "charAt", "toUpperCase", "slice", "test", "replace", "makeCorrectionStage", "correct", "id", "trigger", "window", "blocks", "concurrency", "model", "DEFAULT_STAGE_MODEL", "run", "promise", "pipe", "map", "updates", "StageWrite", "empty", "sync", "block", "index", "filter", "corrected", "undefined", "Effect", "makeDiarizationStage", "id", "trigger", "window", "blocks", "concurrency", "run", "succeed", "StageWrite", "empty", "Effect", "insertReferences", "STOP_WORDS", "Set", "extractProperNouns", "text", "matches", "match", "Array", "from", "filter", "word", "has", "isLinked", "includes", "resolveEntities", "lookup", "nouns", "references", "quotes", "matched", "noun", "candidates", "unambiguous", "length", "score", "push", "ref", "quote", "id", "add", "toLowerCase", "map", "start", "Math", "max", "indexOf", "kind", "end", "linkEntities", "insertReferences", "makeExtractionStage", "trigger", "window", "blocks", "concurrency", "model", "DEFAULT_STAGE_MODEL", "run", "ctx", "gen", "updates", "index", "block", "corrected", "promise", "update", "StageWrite", "empty", "Effect", "makeSummarizationStage", "id", "trigger", "concurrency", "model", "DEFAULT_STAGE_MODEL", "run", "window", "sync", "utterances", "map", "block", "corrected", "text", "trim", "filter", "Boolean", "length", "StageWrite", "empty", "transcript", "summary", "join", "summaryUpdatedAt", "Date", "toISOString", "Effect", "makeTranslationStage", "_targetLanguage", "id", "trigger", "window", "blocks", "concurrency", "model", "DEFAULT_STAGE_MODEL", "run", "succeed", "StageWrite", "empty", "LanguageModel", "Effect", "Layer", "Schema", "AiService", "DXN", "CorrectionPayload", "Struct", "blocks", "Array", "index", "Number", "corrected", "String", "PROMPT", "correctWithLanguageModel", "model", "DEFAULT_STAGE_MODEL", "gen", "input", "map", "block", "text", "join", "response", "generateObject", "schema", "prompt", "value", "pipe", "provide", "AiService", "DXN", "getName", "orDie", "__dxlog_file", "extract", "makeExtractionStage", "summarize", "translate", "diarize", "makeDiarizationStage", "log", "unknown", "known", "STAGE_FACTORIES", "configs", "filter", "config", "enabled"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"inputs":{"src/TranscriptEvent.ts":{"bytes":2330,"imports":[],"format":"esm"},"src/Stage.ts":{"bytes":5434,"imports":[],"format":"esm"},"src/lookup.ts":{"bytes":6109,"imports":[{"path":"@dxos/echo","kind":"import-statement","external":true}],"format":"esm"},"src/PipelineConfig.ts":{"bytes":8404,"imports":[{"path":"effect/Schema","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true}],"format":"esm"},"src/model-routing.ts":{"bytes":2534,"imports":[{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"src/PipelineConfig.ts","kind":"import-statement","original":"./PipelineConfig"}],"format":"esm"},"src/PipelineRuntime.ts":{"bytes":23144,"imports":[{"path":"effect/Cause","kind":"import-statement","external":true},{"path":"effect/Context","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Function","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/pipeline","kind":"import-statement","external":true},{"path":"src/model-routing.ts","kind":"import-statement","original":"./model-routing"}],"format":"esm"},"src/live.ts":{"bytes":6487,"imports":[{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Queue","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"@dxos/effect","kind":"import-statement","external":true},{"path":"src/PipelineRuntime.ts","kind":"import-statement","original":"./PipelineRuntime"},{"path":"src/TranscriptEvent.ts","kind":"import-statement","original":"./TranscriptEvent"}],"format":"esm"},"src/asr/audio-recorder.ts":{"bytes":3065,"imports":[],"format":"esm"},"src/asr/sentence-buffer.ts":{"bytes":10825,"imports":[],"format":"esm"},"src/asr/util.ts":{"bytes":1437,"imports":[],"format":"esm"},"src/asr/transcriber.ts":{"bytes":33097,"imports":[{"path":"wavefile","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/config","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/tracing","kind":"import-statement","external":true},{"path":"src/asr/util.ts","kind":"import-statement","original":"./util"}],"format":"esm"},"src/asr/pipeline.ts":{"bytes":9105,"imports":[{"path":"src/live.ts","kind":"import-statement","original":"../live"},{"path":"src/asr/sentence-buffer.ts","kind":"import-statement","original":"./sentence-buffer"},{"path":"src/asr/transcriber.ts","kind":"import-statement","original":"./transcriber"}],"format":"esm"},"src/asr/index.ts":{"bytes":684,"imports":[{"path":"src/asr/audio-recorder.ts","kind":"import-statement","original":"./audio-recorder"},{"path":"src/asr/sentence-buffer.ts","kind":"import-statement","original":"./sentence-buffer"},{"path":"src/asr/transcriber.ts","kind":"import-statement","original":"./transcriber"},{"path":"src/asr/pipeline.ts","kind":"import-statement","original":"./pipeline"}],"format":"esm"},"src/dispatch.ts":{"bytes":5641,"imports":[{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true}],"format":"esm"},"src/stages/correction.ts":{"bytes":8629,"imports":[{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"src/PipelineConfig.ts","kind":"import-statement","original":"../PipelineConfig"},{"path":"src/Stage.ts","kind":"import-statement","original":"../Stage"}],"format":"esm"},"src/stages/diarization.ts":{"bytes":2278,"imports":[{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"src/Stage.ts","kind":"import-statement","original":"../Stage"}],"format":"esm"},"src/stages/extraction.ts":{"bytes":18037,"imports":[{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"@dxos/assistant/extraction","kind":"import-statement","external":true},{"path":"src/PipelineConfig.ts","kind":"import-statement","original":"../PipelineConfig"},{"path":"src/Stage.ts","kind":"import-statement","original":"../Stage"}],"format":"esm"},"src/stages/summarization.ts":{"bytes":4494,"imports":[{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"src/PipelineConfig.ts","kind":"import-statement","original":"../PipelineConfig"},{"path":"src/Stage.ts","kind":"import-statement","original":"../Stage"}],"format":"esm"},"src/stages/translation.ts":{"bytes":2754,"imports":[{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"src/PipelineConfig.ts","kind":"import-statement","original":"../PipelineConfig"},{"path":"src/Stage.ts","kind":"import-statement","original":"../Stage"}],"format":"esm"},"src/stages/correction-llm.ts":{"bytes":6589,"imports":[{"path":"@effect/ai/LanguageModel","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Layer","kind":"import-statement","external":true},{"path":"effect/Schema","kind":"import-statement","external":true},{"path":"@dxos/ai","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"src/PipelineConfig.ts","kind":"import-statement","original":"../PipelineConfig"}],"format":"esm"},"src/stages/index.ts":{"bytes":6052,"imports":[{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"src/stages/correction.ts","kind":"import-statement","original":"./correction"},{"path":"src/stages/diarization.ts","kind":"import-statement","original":"./diarization"},{"path":"src/stages/extraction.ts","kind":"import-statement","original":"./extraction"},{"path":"src/stages/summarization.ts","kind":"import-statement","original":"./summarization"},{"path":"src/stages/translation.ts","kind":"import-statement","original":"./translation"},{"path":"src/stages/correction.ts","kind":"import-statement","original":"./correction"},{"path":"src/stages/correction-llm.ts","kind":"import-statement","original":"./correction-llm"},{"path":"src/stages/extraction.ts","kind":"import-statement","original":"./extraction"},{"path":"src/stages/summarization.ts","kind":"import-statement","original":"./summarization"},{"path":"src/stages/translation.ts","kind":"import-statement","original":"./translation"},{"path":"src/stages/diarization.ts","kind":"import-statement","original":"./diarization"}],"format":"esm"},"src/index.ts":{"bytes":1201,"imports":[{"path":"src/TranscriptEvent.ts","kind":"import-statement","original":"./TranscriptEvent"},{"path":"src/Stage.ts","kind":"import-statement","original":"./Stage"},{"path":"src/lookup.ts","kind":"import-statement","original":"./lookup"},{"path":"src/PipelineConfig.ts","kind":"import-statement","original":"./PipelineConfig"},{"path":"src/model-routing.ts","kind":"import-statement","original":"./model-routing"},{"path":"src/PipelineRuntime.ts","kind":"import-statement","original":"./PipelineRuntime"},{"path":"src/live.ts","kind":"import-statement","original":"./live"},{"path":"src/asr/index.ts","kind":"import-statement","original":"./asr"},{"path":"src/dispatch.ts","kind":"import-statement","original":"./dispatch"},{"path":"src/stages/index.ts","kind":"import-statement","original":"./stages"}],"format":"esm"},"src/testing/conversation-parser.ts":{"bytes":9800,"imports":[],"format":"esm"},"src/testing/fixtures.ts":{"bytes":2184,"imports":[],"format":"esm"},"src/testing/scripted-source.ts":{"bytes":3209,"imports":[{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"src/TranscriptEvent.ts","kind":"import-statement","original":"../TranscriptEvent"}],"format":"esm"},"src/testing/stream-simulator.ts":{"bytes":14198,"imports":[],"format":"esm"},"src/testing/index.ts":{"bytes":710,"imports":[{"path":"src/testing/conversation-parser.ts","kind":"import-statement","original":"./conversation-parser"},{"path":"src/testing/fixtures.ts","kind":"import-statement","original":"./fixtures"},{"path":"src/testing/scripted-source.ts","kind":"import-statement","original":"./scripted-source"},{"path":"src/testing/stream-simulator.ts","kind":"import-statement","original":"./stream-simulator"}],"format":"esm"}},"outputs":{"dist/lib/neutral/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":80805},"dist/lib/neutral/index.mjs":{"imports":[{"path":"dist/lib/neutral/chunk-Y44GOMGN.mjs","kind":"import-statement"},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"effect/Schema","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"effect/Cause","kind":"import-statement","external":true},{"path":"effect/Context","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Function","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/pipeline","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Queue","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"@dxos/effect","kind":"import-statement","external":true},{"path":"wavefile","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/config","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/tracing","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"@dxos/assistant/extraction","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"@effect/ai/LanguageModel","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Layer","kind":"import-statement","external":true},{"path":"effect/Schema","kind":"import-statement","external":true},{"path":"@dxos/ai","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true}],"exports":["DEFAULT_STAGE_MODEL","PIPELINE_PRESETS","PipelineConfig","PipelineRuntime","STAGE_FACTORIES","SentenceBuffer","StageConfig","StageWrite","Transcriber","TranscriptEvent","alignWhisperSegments","buildStages","captureCommit","correctText","correctWithLanguageModel","extractProperNouns","findPreset","isLinked","linkEntities","makeConfigFromPreset","makeCorrectionStage","makeDatabaseLookup","makeDiarizationStage","makeEchoCommit","makeExtractionStage","makeSummarizationStage","makeTranslationStage","resolveEntities","resolveModel","runAsrPipeline","runLivePipeline","splitSentences"],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0},"src/Stage.ts":{"bytesInOutput":177},"src/lookup.ts":{"bytesInOutput":651},"src/PipelineConfig.ts":{"bytesInOutput":1622},"src/model-routing.ts":{"bytesInOutput":220},"src/PipelineRuntime.ts":{"bytesInOutput":3775},"src/live.ts":{"bytesInOutput":853},"src/asr/sentence-buffer.ts":{"bytesInOutput":2079},"src/asr/transcriber.ts":{"bytesInOutput":7960},"src/asr/util.ts":{"bytesInOutput":267},"src/asr/pipeline.ts":{"bytesInOutput":1199},"src/dispatch.ts":{"bytesInOutput":806},"src/stages/index.ts":{"bytesInOutput":861},"src/stages/correction.ts":{"bytesInOutput":1058},"src/stages/diarization.ts":{"bytesInOutput":306},"src/stages/extraction.ts":{"bytesInOutput":2915},"src/stages/summarization.ts":{"bytesInOutput":561},"src/stages/translation.ts":{"bytesInOutput":376},"src/stages/correction-llm.ts":{"bytesInOutput":1270}},"bytes":28186},"dist/lib/neutral/testing/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":15017},"dist/lib/neutral/testing/index.mjs":{"imports":[{"path":"dist/lib/neutral/chunk-Y44GOMGN.mjs","kind":"import-statement"},{"path":"effect/Stream","kind":"import-statement","external":true}],"exports":["SAMPLE_MEETING","SAMPLE_NOTES","parseConversation","scriptedSource","simulateStream"],"entryPoint":"src/testing/index.ts","inputs":{"src/testing/conversation-parser.ts":{"bytesInOutput":1756},"src/testing/index.ts":{"bytesInOutput":0},"src/testing/fixtures.ts":{"bytesInOutput":382},"src/testing/scripted-source.ts":{"bytesInOutput":406},"src/testing/stream-simulator.ts":{"bytesInOutput":2469}},"bytes":5347},"dist/lib/neutral/chunk-Y44GOMGN.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":1275},"dist/lib/neutral/chunk-Y44GOMGN.mjs":{"imports":[],"exports":["TranscriptEvent"],"inputs":{"src/TranscriptEvent.ts":{"bytesInOutput":397}},"bytes":498}}}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TranscriptEvent
|
|
3
|
+
} from "../chunk-Y44GOMGN.mjs";
|
|
4
|
+
|
|
5
|
+
// src/testing/conversation-parser.ts
|
|
6
|
+
var parseConversation = (input) => {
|
|
7
|
+
const lines = input.split("\n").map((line) => line.replace(/\s+$/, ""));
|
|
8
|
+
const entities = [];
|
|
9
|
+
const utterances = [];
|
|
10
|
+
const speakerOrder = /* @__PURE__ */ new Set();
|
|
11
|
+
let section = "none";
|
|
12
|
+
let currentEntity;
|
|
13
|
+
for (const raw of lines) {
|
|
14
|
+
const line = raw.trim();
|
|
15
|
+
if (line.length === 0 || line.startsWith("#")) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (raw.startsWith("Entities:") || raw.startsWith("Entitites:")) {
|
|
19
|
+
section = "entities";
|
|
20
|
+
currentEntity = void 0;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (raw.startsWith("Conversation:")) {
|
|
24
|
+
section = "conversation";
|
|
25
|
+
currentEntity = void 0;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (section === "entities") {
|
|
29
|
+
const typeMatch = line.match(/^([A-Za-z][A-Za-z0-9_-]*):$/);
|
|
30
|
+
if (typeMatch) {
|
|
31
|
+
currentEntity = {
|
|
32
|
+
kind: typeMatch[1],
|
|
33
|
+
fields: {}
|
|
34
|
+
};
|
|
35
|
+
entities.push(currentEntity);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const fieldMatch = line.match(/^([A-Za-z][A-Za-z0-9_-]*):\s*(.+)$/);
|
|
39
|
+
if (fieldMatch && currentEntity) {
|
|
40
|
+
currentEntity.fields[fieldMatch[1]] = fieldMatch[2];
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (section === "conversation") {
|
|
46
|
+
const utteranceMatch = line.match(/^([^:]+):\s*(.+)$/);
|
|
47
|
+
if (utteranceMatch) {
|
|
48
|
+
const speaker = utteranceMatch[1].trim();
|
|
49
|
+
const text = utteranceMatch[2].trim();
|
|
50
|
+
if (text.length > 0) {
|
|
51
|
+
utterances.push({
|
|
52
|
+
speaker,
|
|
53
|
+
text
|
|
54
|
+
});
|
|
55
|
+
speakerOrder.add(speaker);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (utterances.length === 0) {
|
|
61
|
+
throw new Error("parseConversation: no utterances found");
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
entities,
|
|
65
|
+
utterances,
|
|
66
|
+
speakers: Array.from(speakerOrder)
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// src/testing/fixtures.ts
|
|
71
|
+
var SAMPLE_MEETING = Object.freeze([
|
|
72
|
+
{
|
|
73
|
+
text: "so i think we should ship munich on friday"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
text: "lets confirm the plan with anna first"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
text: "agreed we can review it tomorrow"
|
|
80
|
+
}
|
|
81
|
+
]);
|
|
82
|
+
var SAMPLE_NOTES = Object.freeze([
|
|
83
|
+
{
|
|
84
|
+
text: "remember to email the quarterly report"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
text: "and schedule a follow up with the design team"
|
|
88
|
+
}
|
|
89
|
+
]);
|
|
90
|
+
|
|
91
|
+
// src/testing/scripted-source.ts
|
|
92
|
+
import * as Stream from "effect/Stream";
|
|
93
|
+
var scriptedSource = (blocks, options = {}) => {
|
|
94
|
+
const events = blocks.map((block, index) => TranscriptEvent.block({
|
|
95
|
+
_tag: "transcript",
|
|
96
|
+
started: block.started ?? new Date(index * 1e3).toISOString(),
|
|
97
|
+
text: block.text
|
|
98
|
+
}));
|
|
99
|
+
if (options.silence !== false) {
|
|
100
|
+
events.push(TranscriptEvent.silence(5e3));
|
|
101
|
+
}
|
|
102
|
+
return Stream.fromIterable(events);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// src/testing/stream-simulator.ts
|
|
106
|
+
var simulateStream = (conversation, options = {}) => {
|
|
107
|
+
const wordsPerSecond = options.wordsPerSecond ?? 2.5;
|
|
108
|
+
const gapSeconds = options.gapSeconds ?? 0.5;
|
|
109
|
+
const batchSeconds = options.batchSeconds ?? 0;
|
|
110
|
+
if (!Number.isFinite(wordsPerSecond) || wordsPerSecond <= 0) {
|
|
111
|
+
throw new Error(`simulateStream: wordsPerSecond must be a finite number > 0 (got ${wordsPerSecond}).`);
|
|
112
|
+
}
|
|
113
|
+
if (!Number.isFinite(gapSeconds) || gapSeconds < 0) {
|
|
114
|
+
throw new Error(`simulateStream: gapSeconds must be a finite number >= 0 (got ${gapSeconds}).`);
|
|
115
|
+
}
|
|
116
|
+
if (!Number.isFinite(batchSeconds) || batchSeconds < 0) {
|
|
117
|
+
throw new Error(`simulateStream: batchSeconds must be a finite number >= 0 (got ${batchSeconds}).`);
|
|
118
|
+
}
|
|
119
|
+
const conversationStart = Date.UTC(2024, 0, 1, 12, 0, 0);
|
|
120
|
+
let cursorMs = 0;
|
|
121
|
+
const batches = [];
|
|
122
|
+
const grouped = [];
|
|
123
|
+
if (batchSeconds === 0) {
|
|
124
|
+
for (const u of conversation.utterances) {
|
|
125
|
+
grouped.push({
|
|
126
|
+
speaker: u.speaker,
|
|
127
|
+
utterances: [
|
|
128
|
+
u
|
|
129
|
+
]
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
let pending;
|
|
134
|
+
for (const u of conversation.utterances) {
|
|
135
|
+
const words = utteranceWordCount(u.text);
|
|
136
|
+
if (pending && pending.speaker === u.speaker && pending.words / wordsPerSecond < batchSeconds) {
|
|
137
|
+
pending.utterances.push(u);
|
|
138
|
+
pending.words += words;
|
|
139
|
+
} else {
|
|
140
|
+
if (pending) {
|
|
141
|
+
grouped.push({
|
|
142
|
+
speaker: pending.speaker,
|
|
143
|
+
utterances: pending.utterances
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
pending = {
|
|
147
|
+
speaker: u.speaker,
|
|
148
|
+
utterances: [
|
|
149
|
+
u
|
|
150
|
+
],
|
|
151
|
+
words
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (pending) {
|
|
156
|
+
grouped.push({
|
|
157
|
+
speaker: pending.speaker,
|
|
158
|
+
utterances: pending.utterances
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
for (const group of grouped) {
|
|
163
|
+
const startMs = cursorMs;
|
|
164
|
+
const blocks = [];
|
|
165
|
+
let segmentCursorMs = cursorMs;
|
|
166
|
+
for (const u of group.utterances) {
|
|
167
|
+
const durationMs = Math.max(500, utteranceWordCount(u.text) / wordsPerSecond * 1e3);
|
|
168
|
+
blocks.push({
|
|
169
|
+
_tag: "transcript",
|
|
170
|
+
started: new Date(conversationStart + segmentCursorMs).toISOString(),
|
|
171
|
+
text: u.text
|
|
172
|
+
});
|
|
173
|
+
segmentCursorMs += durationMs;
|
|
174
|
+
}
|
|
175
|
+
batches.push({
|
|
176
|
+
speaker: group.speaker,
|
|
177
|
+
offsetMs: startMs,
|
|
178
|
+
blocks
|
|
179
|
+
});
|
|
180
|
+
cursorMs = segmentCursorMs + gapSeconds * 1e3;
|
|
181
|
+
}
|
|
182
|
+
return batches;
|
|
183
|
+
};
|
|
184
|
+
var utteranceWordCount = (text) => text.trim().split(/\s+/).filter(Boolean).length;
|
|
185
|
+
export {
|
|
186
|
+
SAMPLE_MEETING,
|
|
187
|
+
SAMPLE_NOTES,
|
|
188
|
+
parseConversation,
|
|
189
|
+
scriptedSource,
|
|
190
|
+
simulateStream
|
|
191
|
+
};
|
|
192
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/testing/conversation-parser.ts", "../../../../src/testing/fixtures.ts", "../../../../src/testing/scripted-source.ts", "../../../../src/testing/stream-simulator.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\n// Parser for the human-authored conversation fixture (see `conversation.txt`).\n// Captures both the seed entities (Persons, Organizations, …) and the speaker-tagged\n// dialogue used by `stream-simulator.ts` to feed the pipeline in tests.\n\nexport type ConversationEntity = {\n /** Type name as written in the fixture, e.g. `Person`, `Organization`. */\n kind: string;\n /** Free-form field values; consumers map these to the relevant ECHO schema. */\n fields: Record<string, string>;\n};\n\nexport type ConversationUtterance = {\n /** Speaker label as written in the fixture (e.g. `A`, `B`, `Rich`). */\n speaker: string;\n /** Raw utterance text. */\n text: string;\n};\n\nexport type ParsedConversation = {\n entities: ConversationEntity[];\n utterances: ConversationUtterance[];\n /** Distinct speaker labels in first-seen order. */\n speakers: string[];\n};\n\n/**\n * Parse the on-disk conversation format into structured data.\n *\n * Tolerates leading whitespace inside blocks and ignores blank / `#` comment lines.\n * Throws if the input doesn't contain a `Conversation:` block — `Entities:` is optional.\n */\nexport const parseConversation = (input: string): ParsedConversation => {\n const lines = input.split('\\n').map((line) => line.replace(/\\s+$/, ''));\n\n const entities: ConversationEntity[] = [];\n const utterances: ConversationUtterance[] = [];\n const speakerOrder = new Set<string>();\n\n type Section = 'none' | 'entities' | 'conversation';\n let section: Section = 'none';\n let currentEntity: ConversationEntity | undefined;\n\n for (const raw of lines) {\n const line = raw.trim();\n if (line.length === 0 || line.startsWith('#')) {\n continue;\n }\n\n // Section headers (must be left-aligned to switch sections).\n if (raw.startsWith('Entities:') || raw.startsWith('Entitites:')) {\n // tolerate the typo present in earlier fixtures\n section = 'entities';\n currentEntity = undefined;\n continue;\n }\n if (raw.startsWith('Conversation:')) {\n section = 'conversation';\n currentEntity = undefined;\n continue;\n }\n\n if (section === 'entities') {\n // `<TypeName>:` starts a new entity; nested `<field>: <value>` lines fill it.\n const typeMatch = line.match(/^([A-Za-z][A-Za-z0-9_-]*):$/);\n if (typeMatch) {\n currentEntity = { kind: typeMatch[1], fields: {} };\n entities.push(currentEntity);\n continue;\n }\n const fieldMatch = line.match(/^([A-Za-z][A-Za-z0-9_-]*):\\s*(.+)$/);\n if (fieldMatch && currentEntity) {\n currentEntity.fields[fieldMatch[1]] = fieldMatch[2];\n continue;\n }\n // Silently skip unrecognised lines so authors can add free-form annotations.\n continue;\n }\n\n if (section === 'conversation') {\n const utteranceMatch = line.match(/^([^:]+):\\s*(.+)$/);\n if (utteranceMatch) {\n const speaker = utteranceMatch[1].trim();\n const text = utteranceMatch[2].trim();\n if (text.length > 0) {\n utterances.push({ speaker, text });\n speakerOrder.add(speaker);\n }\n }\n }\n }\n\n if (utterances.length === 0) {\n throw new Error('parseConversation: no utterances found');\n }\n\n return { entities, utterances, speakers: Array.from(speakerOrder) };\n};\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { type ScriptedBlock } from './scripted-source';\n\n/** A short multi-utterance meeting transcript (raw, lower-cased — as Whisper tends to emit). */\nexport const SAMPLE_MEETING: readonly ScriptedBlock[] = Object.freeze([\n { text: 'so i think we should ship munich on friday' },\n { text: 'lets confirm the plan with anna first' },\n { text: 'agreed we can review it tomorrow' },\n]);\n\n/** A single-speaker dictation transcript (for the Notes preset). */\nexport const SAMPLE_NOTES: readonly ScriptedBlock[] = Object.freeze([\n { text: 'remember to email the quarterly report' },\n { text: 'and schedule a follow up with the design team' },\n]);\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Stream from 'effect/Stream';\n\nimport { TranscriptEvent } from '../TranscriptEvent';\n\nexport type ScriptedBlock = { text: string; started?: string };\n\nexport type ScriptedSourceOptions = {\n /** Append a trailing silence event (drives on-silence stages). Default: true. */\n readonly silence?: boolean;\n};\n\n/**\n * Build a deterministic {@link TranscriptEvent} stream from a fixture of blocks. Emits a `block`\n * event per entry, then (by default) a trailing `silence`. No audio or network — for testbench and CI.\n */\nexport const scriptedSource = (\n blocks: readonly ScriptedBlock[],\n options: ScriptedSourceOptions = {},\n): Stream.Stream<TranscriptEvent> => {\n const events: TranscriptEvent[] = blocks.map((block, index) =>\n TranscriptEvent.block({\n _tag: 'transcript',\n started: block.started ?? new Date(index * 1000).toISOString(),\n text: block.text,\n }),\n );\n if (options.silence !== false) {\n events.push(TranscriptEvent.silence(5000));\n }\n return Stream.fromIterable(events);\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\n// Turns a parsed conversation into a chronologically-ordered sequence of Whisper-shaped\n// transcript batches, one per (speaker, utterance) pair. Each batch carries a virtual\n// timestamp (ms since the conversation start) and the speaker label so consumers can fan\n// out per-stream — analogous to two microphones being transcribed in parallel.\n//\n// The simulator does NOT do any wall-clock waiting. Tests drive virtual time via\n// `vi.useFakeTimers()` or step through the batches directly; production code wouldn't use\n// this module at all.\n\nimport { type ContentBlock } from '@dxos/types';\n\nimport type { ConversationUtterance, ParsedConversation } from './conversation-parser';\n\nexport type StreamSimulatorOptions = {\n /**\n * Average speaking rate, words per second. Used to assign a virtual duration to each\n * utterance so consecutive utterances land at realistic offsets.\n * @default 2.5 (≈150 wpm — typical conversational pace)\n */\n wordsPerSecond?: number;\n\n /**\n * Gap between consecutive utterances in seconds. Models a brief pause for turn-taking\n * even when speakers don't actually overlap.\n * @default 0.5\n */\n gapSeconds?: number;\n\n /**\n * Whisper batches typically arrive in chunks of N seconds rather than per-utterance.\n * When set, utterances shorter than `batchSeconds` are merged into the same batch as\n * the following utterance from the same speaker. `0` disables merging — every utterance\n * is its own batch.\n * @default 0\n */\n batchSeconds?: number;\n};\n\nexport type SimulatedBatch = {\n /** Speaker label from the fixture (`A`, `B`, …). Maps to a virtual `identityDid`. */\n speaker: string;\n /** ms offset from the conversation start when this batch is delivered. */\n offsetMs: number;\n /** Whisper-shaped transcript blocks (raw text, no enrichment). */\n blocks: ContentBlock.Transcript[];\n};\n\n/**\n * Build the chronological batch schedule for a parsed conversation. The result is a\n * pure data structure — consumers iterate and drive virtual time themselves.\n */\nexport const simulateStream = (\n conversation: ParsedConversation,\n options: StreamSimulatorOptions = {},\n): SimulatedBatch[] => {\n const wordsPerSecond = options.wordsPerSecond ?? 2.5;\n const gapSeconds = options.gapSeconds ?? 0.5;\n const batchSeconds = options.batchSeconds ?? 0;\n\n // Guard against divide-by-zero / NaN / negative inputs — `wordsPerSecond` divides into a\n // duration below, and the other knobs feed into offsets that must be finite.\n if (!Number.isFinite(wordsPerSecond) || wordsPerSecond <= 0) {\n throw new Error(`simulateStream: wordsPerSecond must be a finite number > 0 (got ${wordsPerSecond}).`);\n }\n if (!Number.isFinite(gapSeconds) || gapSeconds < 0) {\n throw new Error(`simulateStream: gapSeconds must be a finite number >= 0 (got ${gapSeconds}).`);\n }\n if (!Number.isFinite(batchSeconds) || batchSeconds < 0) {\n throw new Error(`simulateStream: batchSeconds must be a finite number >= 0 (got ${batchSeconds}).`);\n }\n\n const conversationStart = Date.UTC(2024, 0, 1, 12, 0, 0); // deterministic, ignored by callers\n let cursorMs = 0;\n const batches: SimulatedBatch[] = [];\n\n // Optionally merge same-speaker consecutive utterances until they reach `batchSeconds`.\n const grouped: { speaker: string; utterances: ConversationUtterance[] }[] = [];\n if (batchSeconds === 0) {\n for (const u of conversation.utterances) {\n grouped.push({ speaker: u.speaker, utterances: [u] });\n }\n } else {\n let pending: { speaker: string; utterances: ConversationUtterance[]; words: number } | undefined;\n for (const u of conversation.utterances) {\n const words = utteranceWordCount(u.text);\n if (pending && pending.speaker === u.speaker && pending.words / wordsPerSecond < batchSeconds) {\n pending.utterances.push(u);\n pending.words += words;\n } else {\n if (pending) {\n grouped.push({ speaker: pending.speaker, utterances: pending.utterances });\n }\n pending = { speaker: u.speaker, utterances: [u], words };\n }\n }\n if (pending) {\n grouped.push({ speaker: pending.speaker, utterances: pending.utterances });\n }\n }\n\n for (const group of grouped) {\n const startMs = cursorMs;\n const blocks: ContentBlock.Transcript[] = [];\n let segmentCursorMs = cursorMs;\n for (const u of group.utterances) {\n const durationMs = Math.max(500, (utteranceWordCount(u.text) / wordsPerSecond) * 1_000);\n blocks.push({\n _tag: 'transcript',\n started: new Date(conversationStart + segmentCursorMs).toISOString(),\n text: u.text,\n });\n segmentCursorMs += durationMs;\n }\n batches.push({ speaker: group.speaker, offsetMs: startMs, blocks });\n cursorMs = segmentCursorMs + gapSeconds * 1_000;\n }\n\n return batches;\n};\n\nconst utteranceWordCount = (text: string): number => text.trim().split(/\\s+/).filter(Boolean).length;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["parseConversation", "input", "lines", "split", "map", "line", "replace", "entities", "utterances", "speakerOrder", "Set", "section", "currentEntity", "raw", "trim", "length", "startsWith", "undefined", "typeMatch", "match", "kind", "fields", "push", "fieldMatch", "utteranceMatch", "speaker", "text", "add", "Error", "speakers", "Array", "from", "SAMPLE_MEETING", "Object", "freeze", "text", "SAMPLE_NOTES", "Stream", "scriptedSource", "blocks", "options", "events", "map", "block", "index", "TranscriptEvent", "_tag", "started", "Date", "toISOString", "text", "silence", "push", "fromIterable", "simulateStream", "conversation", "options", "wordsPerSecond", "gapSeconds", "batchSeconds", "Number", "isFinite", "Error", "conversationStart", "Date", "UTC", "cursorMs", "batches", "grouped", "u", "utterances", "push", "speaker", "pending", "words", "utteranceWordCount", "text", "group", "startMs", "blocks", "segmentCursorMs", "durationMs", "Math", "max", "_tag", "started", "toISOString", "offsetMs", "trim", "split", "filter", "Boolean", "length"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as Schema from 'effect/Schema';
|
|
2
|
+
import { DXN, Type } from '@dxos/echo';
|
|
3
|
+
/** Cheap, fast default for all stages; same model used by `update-chat-name` / `qualifier`. */
|
|
4
|
+
export declare const DEFAULT_STAGE_MODEL: DXN.DXN;
|
|
5
|
+
/** Per-stage configuration entry within a {@link PipelineConfig}. */
|
|
6
|
+
export declare const StageConfig: Schema.Struct<{
|
|
7
|
+
/** Stage id (matches a registered `Stage.id`). */
|
|
8
|
+
id: typeof Schema.String;
|
|
9
|
+
enabled: typeof Schema.Boolean;
|
|
10
|
+
/** Optional per-stage model override (an NSID name); resolved by the runtime. */
|
|
11
|
+
model: Schema.optional<Schema.Schema<string, string, never>>;
|
|
12
|
+
/** Optional sliding-window override in blocks. Positive integer; bad values fail validation. */
|
|
13
|
+
window: Schema.optional<Schema.Struct<{
|
|
14
|
+
blocks: Schema.filter<Schema.filter<typeof Schema.Number>>;
|
|
15
|
+
}>>;
|
|
16
|
+
}>;
|
|
17
|
+
export type StageConfig = Schema.Schema.Type<typeof StageConfig>;
|
|
18
|
+
declare const PipelineConfig_base: Type.ObjClass<PipelineConfig, {
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly stages: {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly enabled: boolean;
|
|
23
|
+
readonly model?: string | undefined;
|
|
24
|
+
readonly window?: {
|
|
25
|
+
readonly blocks: number;
|
|
26
|
+
} | undefined;
|
|
27
|
+
}[];
|
|
28
|
+
}, {}>;
|
|
29
|
+
/**
|
|
30
|
+
* Ordered, persisted configuration that drives a {@link PipelineRuntime}: which stages run, in what
|
|
31
|
+
* order, with which model and window. Presets ("Meeting", "Notes") are seeded instances.
|
|
32
|
+
*/
|
|
33
|
+
export declare class PipelineConfig extends PipelineConfig_base {
|
|
34
|
+
}
|
|
35
|
+
/** A plain preset descriptor (used to seed a {@link PipelineConfig} object). */
|
|
36
|
+
export type PipelinePreset = {
|
|
37
|
+
name: string;
|
|
38
|
+
stages: StageConfig[];
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Built-in presets. `Meeting` runs the three real stages; `Notes` runs correction (+ extraction)
|
|
42
|
+
* and streams into the editor without a cumulative summary.
|
|
43
|
+
*/
|
|
44
|
+
export declare const PIPELINE_PRESETS: readonly PipelinePreset[];
|
|
45
|
+
export declare const findPreset: (name: string) => PipelinePreset | undefined;
|
|
46
|
+
/** Instantiate a `PipelineConfig` ECHO object from a preset descriptor. */
|
|
47
|
+
export declare const makeConfigFromPreset: (preset: PipelinePreset) => PipelineConfig;
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=PipelineConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PipelineConfig.d.ts","sourceRoot":"","sources":["../../../src/PipelineConfig.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,GAAG,EAAO,IAAI,EAAE,MAAM,YAAY,CAAC;AAE5C,+FAA+F;AAC/F,eAAO,MAAM,mBAAmB,EAAE,GAAG,CAAC,GAA8D,CAAC;AAErG,qEAAqE;AACrE,eAAO,MAAM,WAAW;IACtB,kDAAkD;;;IAGlD,iFAAiF;;IAEjF,gGAAgG;;;;EAEhG,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,WAAW,CAAC,CAAC;;;;;;;;;;;;AAEjE;;;GAGG;AACH,qBAAa,cAAe,SAAQ,mBAOnC;CAAG;AAEJ,gFAAgF;AAChF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,cAAc,EAiBpD,CAAC;AAEH,eAAO,MAAM,UAAU,SAAU,MAAM,KAAG,cAAc,GAAG,SACF,CAAC;AAE1D,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,WAAY,cAAc,KAAG,cACyC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PipelineConfig.test.d.ts","sourceRoot":"","sources":["../../../src/PipelineConfig.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import * as Stream from 'effect/Stream';
|
|
3
|
+
import { DXN } from '@dxos/echo';
|
|
4
|
+
import { type ContentBlock } from '@dxos/types';
|
|
5
|
+
import { type EntityLookup } from './lookup';
|
|
6
|
+
import { type StageConfig } from './PipelineConfig';
|
|
7
|
+
import { type Stage, type StageWrite } from './Stage';
|
|
8
|
+
import { type TranscriptEvent } from './TranscriptEvent';
|
|
9
|
+
/**
|
|
10
|
+
* Commits a stage's output to storage. Receives the exact window slice the stage was invoked with,
|
|
11
|
+
* so `BlockUpdate.index` can be resolved against the originating blocks.
|
|
12
|
+
*/
|
|
13
|
+
export type CommitFn = (write: StageWrite, window: readonly ContentBlock.Transcript[]) => Effect.Effect<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Outcome reported per stage invocation. The `sliding`/`dropping` overflow model has no fiber-level
|
|
16
|
+
* signal for stale work, so only `committed` and `error` are reported (the previous fiber-based
|
|
17
|
+
* runtime also surfaced `interrupted`/`skipped`).
|
|
18
|
+
*/
|
|
19
|
+
export type StageOutcome = 'committed' | 'error';
|
|
20
|
+
export type TelemetryEvent = {
|
|
21
|
+
readonly stageId: string;
|
|
22
|
+
readonly model: DXN.DXN;
|
|
23
|
+
readonly trigger: TranscriptEvent['kind'];
|
|
24
|
+
readonly durationMs: number;
|
|
25
|
+
readonly outcome: StageOutcome;
|
|
26
|
+
};
|
|
27
|
+
export type RunOptions = {
|
|
28
|
+
/** The continuous transcript event stream (ASR source or a scripted fixture). */
|
|
29
|
+
readonly source: Stream.Stream<TranscriptEvent>;
|
|
30
|
+
/** Ordered stages to run. */
|
|
31
|
+
readonly stages: readonly Stage<any, any>[];
|
|
32
|
+
/** Sink for stage outputs (in-memory capture in tests; ECHO dispatcher in production). */
|
|
33
|
+
readonly commit: CommitFn;
|
|
34
|
+
/** Entity-reference resolver injected into each stage context (backend-agnostic). */
|
|
35
|
+
readonly lookup?: EntityLookup;
|
|
36
|
+
/** Per-stage configuration (enabled / model / window). Absent → stage runs with its defaults. */
|
|
37
|
+
readonly configs?: readonly StageConfig[];
|
|
38
|
+
/** Default model when neither config nor stage specifies one. */
|
|
39
|
+
readonly presetDefault?: DXN.DXN;
|
|
40
|
+
/** Optional telemetry sink (drives the testbench). */
|
|
41
|
+
readonly onTelemetry?: (event: TelemetryEvent) => void;
|
|
42
|
+
};
|
|
43
|
+
export declare const PipelineRuntime: Readonly<{
|
|
44
|
+
run: (options: RunOptions) => Effect.Effect<void>;
|
|
45
|
+
}>;
|
|
46
|
+
//# sourceMappingURL=PipelineRuntime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PipelineRuntime.d.ts","sourceRoot":"","sources":["../../../src/PipelineRuntime.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAGjC,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,KAAK,KAAK,EAAqB,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACzE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAQzD;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,YAAY,CAAC,UAAU,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAE9G;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC;AAEjD,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAChD,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;IAC5C,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,qFAAqF;IACrF,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,iGAAiG;IACjG,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,iEAAiE;IACjE,QAAQ,CAAC,aAAa,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;IACjC,sDAAsD;IACtD,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CACxD,CAAC;AAgIF,eAAO,MAAM,eAAe;mBAnCN,UAAU,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;EAmCD,CAAC"}
|