@breadstone/archipel-mcp 0.0.52 → 0.0.53
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/data/guides/ai-realtime-voice.md +506 -0
- package/data/guides/ai-text-generation.md +5 -0
- package/data/guides/health-indicators.md +12 -3
- package/data/guides/index.md +5 -4
- package/data/packages/platform-health/index.md +1 -1
- package/data/packages/platform-intelligence/api/Class.IntelligenceHealthIndicator.md +6 -5
- package/data/packages/platform-intelligence/api/Class.IntelligenceModule.md +2 -2
- package/data/packages/platform-intelligence/api/Class.IntelligenceRealtimeError.md +110 -0
- package/data/packages/platform-intelligence/api/Class.IntelligenceRealtimeMeteringPort.md +47 -0
- package/data/packages/platform-intelligence/api/Class.IntelligenceRealtimeSessionFactory.md +129 -0
- package/data/packages/platform-intelligence/api/Class.IntelligenceRealtimeSessionPort.md +308 -0
- package/data/packages/platform-intelligence/api/Class.IntelligenceTextGenerator.md +6 -6
- package/data/packages/platform-intelligence/api/Function.loadGoogleRealtimeModel.md +25 -0
- package/data/packages/platform-intelligence/api/Function.loadGrokRealtimeModel.md +25 -0
- package/data/packages/platform-intelligence/api/Function.loadOpenAIRealtimeModel.md +25 -0
- package/data/packages/platform-intelligence/api/Interface.IIntelligenceModuleOptions.md +18 -6
- package/data/packages/platform-intelligence/api/Interface.IIntelligenceRealtimeAudioFormat.md +34 -0
- package/data/packages/platform-intelligence/api/Interface.IIntelligenceRealtimeCloseEvent.md +40 -0
- package/data/packages/platform-intelligence/api/Interface.IIntelligenceRealtimeModuleOptions.md +120 -0
- package/data/packages/platform-intelligence/api/Interface.IIntelligenceRealtimeSessionConfiguration.md +135 -0
- package/data/packages/platform-intelligence/api/Interface.IIntelligenceRealtimeSessionOptions.md +148 -0
- package/data/packages/platform-intelligence/api/Interface.IIntelligenceRealtimeToolDefinition.md +58 -0
- package/data/packages/platform-intelligence/api/Interface.IIntelligenceRealtimeTranscriptionConfiguration.md +46 -0
- package/data/packages/platform-intelligence/api/Interface.IIntelligenceRealtimeTurnDetectionConfiguration.md +58 -0
- package/data/packages/platform-intelligence/api/Interface.IIntelligenceRealtimeUsage.md +103 -0
- package/data/packages/platform-intelligence/api/TypeAlias.IntelligenceRealtimeClientEvent.md +64 -0
- package/data/packages/platform-intelligence/api/TypeAlias.IntelligenceRealtimeMetadataValue.md +14 -0
- package/data/packages/platform-intelligence/api/TypeAlias.IntelligenceRealtimeMeteringEvent.md +44 -0
- package/data/packages/platform-intelligence/api/TypeAlias.IntelligenceRealtimeModelLoader.md +25 -0
- package/data/packages/platform-intelligence/api/TypeAlias.IntelligenceRealtimeModelLoaders.md +14 -0
- package/data/packages/platform-intelligence/api/TypeAlias.IntelligenceRealtimeServerEvent.md +159 -0
- package/data/packages/platform-intelligence/api/TypeAlias.IntelligenceRealtimeStatus.md +14 -0
- package/data/packages/platform-intelligence/api/index.md +23 -0
- package/data/packages/platform-intelligence/index.md +133 -7
- package/data/patterns/index.md +1 -0
- package/data/patterns/realtime-session-pattern.md +309 -0
- package/package.json +1 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: platform-intelligence
|
|
3
|
-
description: Multi-provider AI text generation, streaming, and tool calling.
|
|
3
|
+
description: Multi-provider AI text generation, streaming, realtime voice, metering, and tool calling.
|
|
4
4
|
order: 16
|
|
5
|
-
tags: [intelligence, ai, openai, anthropic, google, grok, text-generation, streaming, tool-calling, health]
|
|
5
|
+
tags: [intelligence, ai, openai, anthropic, google, grok, text-generation, streaming, realtime, voice, metering, tool-calling, health]
|
|
6
6
|
package: '@breadstone/archipel-platform-intelligence'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# platform-intelligence
|
|
10
10
|
|
|
11
|
-
Multi-provider AI text generation
|
|
11
|
+
Multi-provider AI library supporting text generation and server-owned realtime voice sessions through OpenAI, Anthropic, Google Generative AI, and Grok. Tool orchestration is delegated to the AI SDK through native and provider-defined tool definitions, `toolChoice`, `activeTools`, and `stopWhen`. Advanced use cases can pass native AI SDK prompts, request-level models, provider options, headers, telemetry, output settings, and step hooks through the platform generator.
|
|
12
12
|
|
|
13
13
|
**Package:** `@breadstone/archipel-platform-intelligence`
|
|
14
14
|
|
|
@@ -35,6 +35,126 @@ export class AppModule {}
|
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
38
|
+
## Realtime Voice
|
|
39
|
+
|
|
40
|
+
Archipel owns the upstream provider WebSocket and exposes normalized audio,
|
|
41
|
+
text, transcription, response, and tool events through
|
|
42
|
+
`IntelligenceRealtimeSessionPort`. The consuming backend can place its normal
|
|
43
|
+
authentication, authorization, tenant isolation, persistence, and client
|
|
44
|
+
WebSocket in front of this port. Provider credentials and short-lived tokens
|
|
45
|
+
never need to reach the browser.
|
|
46
|
+
|
|
47
|
+
The complete application integration is documented in
|
|
48
|
+
[AI Realtime Voice](/guides/ai-realtime-voice); the reusable ownership,
|
|
49
|
+
durability, and recovery rules are documented in the
|
|
50
|
+
[Realtime Session Pattern](/patterns/realtime-session-pattern).
|
|
51
|
+
|
|
52
|
+
The implementation uses the experimental realtime model contract in Vercel AI
|
|
53
|
+
SDK 7. OpenAI, Google, and xAI are loaded through Archipel provider subpaths;
|
|
54
|
+
consuming applications do not import the official OpenAI SDK or make direct
|
|
55
|
+
provider calls.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { Injectable, Module } from '@nestjs/common';
|
|
59
|
+
import {
|
|
60
|
+
IntelligenceModule,
|
|
61
|
+
IntelligenceProviderNames,
|
|
62
|
+
} from '@breadstone/archipel-platform-intelligence';
|
|
63
|
+
import {
|
|
64
|
+
IntelligenceRealtimeMeteringPort,
|
|
65
|
+
IntelligenceRealtimeSessionFactory,
|
|
66
|
+
type IntelligenceRealtimeMeteringEvent,
|
|
67
|
+
} from '@breadstone/archipel-platform-intelligence/realtime';
|
|
68
|
+
import { loadOpenAIRealtimeModel } from '@breadstone/archipel-platform-intelligence/providers/openai';
|
|
69
|
+
import { loadGoogleRealtimeModel } from '@breadstone/archipel-platform-intelligence/providers/google';
|
|
70
|
+
import { loadGrokRealtimeModel } from '@breadstone/archipel-platform-intelligence/providers/grok';
|
|
71
|
+
|
|
72
|
+
@Injectable()
|
|
73
|
+
export class RealtimeMeteringAdapter extends IntelligenceRealtimeMeteringPort {
|
|
74
|
+
public async report(event: IntelligenceRealtimeMeteringEvent): Promise<void> {
|
|
75
|
+
await persistIdempotently(event.eventId, event);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@Module({
|
|
80
|
+
imports: [
|
|
81
|
+
IntelligenceModule.register({
|
|
82
|
+
validateOnModuleInit: false,
|
|
83
|
+
realtime: {
|
|
84
|
+
providerLoaders: {
|
|
85
|
+
[IntelligenceProviderNames.OpenAI]: loadOpenAIRealtimeModel,
|
|
86
|
+
[IntelligenceProviderNames.Google]: loadGoogleRealtimeModel,
|
|
87
|
+
[IntelligenceProviderNames.Grok]: loadGrokRealtimeModel,
|
|
88
|
+
},
|
|
89
|
+
meteringAdapter: RealtimeMeteringAdapter,
|
|
90
|
+
meteringIntervalMs: 30_000,
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
],
|
|
94
|
+
})
|
|
95
|
+
export class RealtimeModule {}
|
|
96
|
+
|
|
97
|
+
@Injectable()
|
|
98
|
+
export class RealtimeConsultationService {
|
|
99
|
+
public constructor(private readonly sessions: IntelligenceRealtimeSessionFactory) {}
|
|
100
|
+
|
|
101
|
+
public async open(consultationId: string): Promise<void> {
|
|
102
|
+
const session = await this.sessions.createSession({
|
|
103
|
+
sessionId: consultationId,
|
|
104
|
+
model: 'gpt-realtime',
|
|
105
|
+
sessionConfiguration: {
|
|
106
|
+
instructions: 'Transcribe the consultation and answer concisely.',
|
|
107
|
+
inputAudioFormat: { type: 'audio/pcm', rate: 24_000 },
|
|
108
|
+
inputAudioTranscription: {},
|
|
109
|
+
outputModalities: ['text', 'audio'],
|
|
110
|
+
turnDetection: { type: 'server-vad' },
|
|
111
|
+
},
|
|
112
|
+
onEvent: forwardToAuthenticatedClient,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
await session.connect();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
| Provider | Archipel loader | Example model |
|
|
121
|
+
| --- | --- | --- |
|
|
122
|
+
| OpenAI | `loadOpenAIRealtimeModel` | `gpt-realtime` |
|
|
123
|
+
| Google | `loadGoogleRealtimeModel` | `gemini-3.1-flash-live-preview` |
|
|
124
|
+
| xAI / Grok | `loadGrokRealtimeModel` | `grok-voice-latest` |
|
|
125
|
+
|
|
126
|
+
### Metering and audit
|
|
127
|
+
|
|
128
|
+
The application-supplied `IntelligenceRealtimeMeteringPort` receives four
|
|
129
|
+
idempotently identifiable event types:
|
|
130
|
+
|
|
131
|
+
| Event | Meaning |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| `session-started` | One upstream provider connection opened |
|
|
134
|
+
| `billing-interval` | Elapsed provider-independent usage, every 30 seconds by default and once more for the final partial interval |
|
|
135
|
+
| `provider-usage` | Exact token and modality counts when present in the raw provider event |
|
|
136
|
+
| `session-ended` | Connection duration and close reason |
|
|
137
|
+
|
|
138
|
+
An application can debit its own token ledger and append its AI audit log in
|
|
139
|
+
the same transaction keyed by `eventId`. Time-based charging remains available
|
|
140
|
+
when a provider omits exact usage; exact token usage remains available for cost
|
|
141
|
+
reconciliation when reported.
|
|
142
|
+
|
|
143
|
+
### Failure and persistence rules
|
|
144
|
+
|
|
145
|
+
- Provider token requests and WebSocket setup are capped at five seconds and
|
|
146
|
+
transient token creation is retried at most twice.
|
|
147
|
+
- Inbound, outbound, metering, and WebSocket buffers are bounded.
|
|
148
|
+
- Normalized events preserve provider wire order.
|
|
149
|
+
- Nest shutdown closes all owned sessions and flushes metering.
|
|
150
|
+
- Archipel does not silently reconnect a lost provider conversation because a
|
|
151
|
+
new connection has different conversational state.
|
|
152
|
+
- The consuming application must persist audio chunks and transcript progress
|
|
153
|
+
durably before acknowledging them, then reconstruct context when it opens a
|
|
154
|
+
replacement provider session.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
38
158
|
## Provider Subpaths
|
|
39
159
|
|
|
40
160
|
Import only the providers you need:
|
|
@@ -359,11 +479,12 @@ All errors are wrapped in `IntelligenceProviderError` with `provider`, `model`,
|
|
|
359
479
|
|
|
360
480
|
## Error Handling
|
|
361
481
|
|
|
362
|
-
The library provides
|
|
482
|
+
The library provides domain error classes for different failure scenarios:
|
|
363
483
|
|
|
364
484
|
| Error class | Code | When thrown |
|
|
365
485
|
| ---------------------------------- | ----------------------------- | --------------------------------------------------------------------- |
|
|
366
486
|
| `IntelligenceProviderError` | `INTELLIGENCE_PROVIDER` | Provider SDK failures during text generation |
|
|
487
|
+
| `IntelligenceRealtimeError` | Realtime phase metadata | Configuration, token, connect, send, receive, metering, or close failures |
|
|
367
488
|
| `IntelligenceValidationError` | `INTELLIGENCE_VALIDATION` | Invalid generation parameters (temperature, topP, maxOutputTokens) |
|
|
368
489
|
| `IntelligenceConfigurationError` | `INTELLIGENCE_CONFIGURATION` | Unsupported provider, missing API key, or missing provider loader |
|
|
369
490
|
|
|
@@ -379,7 +500,12 @@ import {
|
|
|
379
500
|
|
|
380
501
|
## Lifecycle
|
|
381
502
|
|
|
382
|
-
`IntelligenceTextGenerator` implements `OnModuleInit` and validates the provider configuration plus registered provider loader eagerly at startup. Missing API keys, unsupported providers, or missing loaders throw `IntelligenceConfigurationError` before the first request is processed.
|
|
503
|
+
`IntelligenceTextGenerator` implements `OnModuleInit` and validates the provider configuration plus registered provider loader eagerly at startup. Missing API keys, unsupported providers, or missing loaders throw `IntelligenceConfigurationError` before the first request is processed. `IntelligenceRealtimeSessionFactory` implements `OnModuleDestroy`, closes all owned provider WebSockets, and flushes queued metering on shutdown.
|
|
504
|
+
|
|
505
|
+
Set `validateOnModuleInit: false` for a realtime-only module because that option
|
|
506
|
+
controls eager text-model initialization. When text and realtime are both
|
|
507
|
+
used, register the language-model loaders and keep the default eager
|
|
508
|
+
validation.
|
|
383
509
|
|
|
384
510
|
---
|
|
385
511
|
|
|
@@ -391,7 +517,7 @@ import {
|
|
|
391
517
|
|
|
392
518
|
## Health Check
|
|
393
519
|
|
|
394
|
-
The `IntelligenceHealthIndicator` verifies that provider configuration can be resolved. If
|
|
520
|
+
The `IntelligenceHealthIndicator` verifies that provider configuration can be resolved and reports registered realtime providers plus active session count. If neither text nor realtime infrastructure is available, it reports `disabled: true`. Import it from the `/health` subpath:
|
|
395
521
|
|
|
396
522
|
```typescript
|
|
397
523
|
import { IntelligenceModule, IntelligenceProviderNames } from '@breadstone/archipel-platform-intelligence';
|
|
@@ -414,7 +540,7 @@ export class AppModule {}
|
|
|
414
540
|
|
|
415
541
|
| Key | Check | Dependencies |
|
|
416
542
|
| --- | ----- | ------------ |
|
|
417
|
-
| `intelligence` | `up` when provider configuration resolves, else `down
|
|
543
|
+
| `intelligence` | `up` when provider configuration resolves, else `down`; includes realtime readiness when registered | `@Optional() IntelligenceTextGenerator`, `@Optional() IntelligenceRealtimeSessionFactory` |
|
|
418
544
|
|
|
419
545
|
---
|
|
420
546
|
|
package/data/patterns/index.md
CHANGED
|
@@ -19,3 +19,4 @@ These patterns document repeatable implementation shapes used across Archipel. U
|
|
|
19
19
|
| [Repository Pattern](./repository-pattern) | `RepositoryBase` subclasses and Prisma delegate isolation. |
|
|
20
20
|
| [Testing Pattern](./testing-pattern) | Vitest structure, mocks, and integration test conventions. |
|
|
21
21
|
| [Bootstrap Pattern](./bootstrap-pattern) | Composable NestJS startup with `PlatformApplication` and `PlatformBootstrapStep`. |
|
|
22
|
+
| [Realtime Session Pattern](./realtime-session-pattern) | Long-lived connection ownership, per-fragment durability, metering, backpressure, and recovery. |
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Realtime Session Pattern
|
|
3
|
+
description: Ownership, durability, metering, backpressure, and recovery rules for long-lived bidirectional provider sessions.
|
|
4
|
+
order: 11
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Archipel Realtime Session Pattern
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A realtime session is a long-lived, bidirectional connection to an external
|
|
12
|
+
provider. Unlike a normal request, it can outlive access-token refreshes,
|
|
13
|
+
client network changes, deployments, and individual HTTP transactions. Its
|
|
14
|
+
correctness therefore depends on explicit ownership, durable checkpoints,
|
|
15
|
+
bounded queues, idempotent accounting, and visible reconnects.
|
|
16
|
+
|
|
17
|
+
`platform-intelligence` applies this pattern to live AI audio and text through
|
|
18
|
+
`IntelligenceRealtimeSessionFactory` and
|
|
19
|
+
`IntelligenceRealtimeSessionPort`. The same rules apply to other long-lived
|
|
20
|
+
provider streams.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Canonical Topology
|
|
25
|
+
|
|
26
|
+
```mermaid
|
|
27
|
+
flowchart LR
|
|
28
|
+
Client[Client capture and playback]
|
|
29
|
+
ClientQueue[Local durable chunk queue]
|
|
30
|
+
Gateway[Authenticated application gateway]
|
|
31
|
+
DomainStore[Durable domain state]
|
|
32
|
+
Metering[Idempotent ledger and audit adapter]
|
|
33
|
+
SessionPort[Provider-neutral session port]
|
|
34
|
+
Upstream[External realtime provider]
|
|
35
|
+
|
|
36
|
+
Client --> ClientQueue
|
|
37
|
+
ClientQueue <--> Gateway
|
|
38
|
+
Gateway <--> DomainStore
|
|
39
|
+
Gateway <--> SessionPort
|
|
40
|
+
SessionPort --> Metering
|
|
41
|
+
SessionPort <--> Upstream
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The platform library owns the upstream provider connection. The application
|
|
45
|
+
owns the client-facing transport and all business state. The client owns media
|
|
46
|
+
capture and the last local copy of data not yet acknowledged by the
|
|
47
|
+
application.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Invariant 1: Separate Logical and Physical Identity
|
|
52
|
+
|
|
53
|
+
Never use one identifier for both the durable conversation and a provider
|
|
54
|
+
socket.
|
|
55
|
+
|
|
56
|
+
| Identity | Changes on reconnect | Used for |
|
|
57
|
+
| --- | --- | --- |
|
|
58
|
+
| Logical session ID | No | Authorization, domain persistence, customer-visible history |
|
|
59
|
+
| Connection ID | Yes | Provider attempt, metering idempotency, diagnostics, close history |
|
|
60
|
+
|
|
61
|
+
One logical session may have many sequential provider connections. Every
|
|
62
|
+
connection start and end must remain visible in the audit trail.
|
|
63
|
+
|
|
64
|
+
In `platform-intelligence`, these identities are `sessionId` and
|
|
65
|
+
`connectionId`.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Invariant 2: One Owner Per Active Connection
|
|
70
|
+
|
|
71
|
+
An upstream WebSocket and its event queues live in one process. All commands
|
|
72
|
+
for that connection must reach the owning process and execute in order.
|
|
73
|
+
|
|
74
|
+
Acceptable cluster strategies include:
|
|
75
|
+
|
|
76
|
+
- sticky client routing for the active gateway connection;
|
|
77
|
+
- a distributed ownership record mapping connection ID to pod;
|
|
78
|
+
- a dedicated realtime worker selected before the client begins streaming.
|
|
79
|
+
|
|
80
|
+
The in-memory factory registry is a process-local lifecycle mechanism, not a
|
|
81
|
+
distributed session store. Durable business state must never depend on it.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Invariant 3: Persist Small Units While Streaming
|
|
86
|
+
|
|
87
|
+
Durability must not turn realtime media into a deferred upload. Split the
|
|
88
|
+
stream into small ordered fragments and persist each fragment before it is
|
|
89
|
+
acknowledged.
|
|
90
|
+
|
|
91
|
+
```mermaid
|
|
92
|
+
sequenceDiagram
|
|
93
|
+
participant Capture as Client capture
|
|
94
|
+
participant Local as Local durable queue
|
|
95
|
+
participant Gateway as Application gateway
|
|
96
|
+
participant Store as Durable application store
|
|
97
|
+
participant Port as Realtime session port
|
|
98
|
+
participant Provider as Provider
|
|
99
|
+
|
|
100
|
+
Capture->>Local: Write chunk (chunkId, sequence, audio)
|
|
101
|
+
Local->>Gateway: Send chunk
|
|
102
|
+
Gateway->>Store: Insert idempotently
|
|
103
|
+
Store-->>Gateway: Durable
|
|
104
|
+
Gateway->>Port: appendAudio(audio)
|
|
105
|
+
Port->>Provider: Forward immediately
|
|
106
|
+
Port-->>Gateway: Accepted
|
|
107
|
+
Gateway-->>Local: Acknowledge chunkId
|
|
108
|
+
Local->>Local: Remove acknowledged chunk
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The local write protects against a browser or network failure. The application
|
|
112
|
+
write protects against gateway restarts and provides the source for recovery.
|
|
113
|
+
The provider call remains live because this happens per fragment rather than
|
|
114
|
+
after the complete recording.
|
|
115
|
+
|
|
116
|
+
### Chunk-envelope rules
|
|
117
|
+
|
|
118
|
+
- The application envelope contains a stable `chunkId` and monotonic
|
|
119
|
+
`sequence`.
|
|
120
|
+
- Persistence uses `(logicalSessionId, chunkId)` as an idempotency key.
|
|
121
|
+
- The durable record distinguishes `pending` from `forwarded`. A duplicate of
|
|
122
|
+
a forwarded chunk is acknowledged without another upstream write; a pending
|
|
123
|
+
chunk still needs forwarding.
|
|
124
|
+
- Gaps stop acknowledgement until the application's ordering policy resolves
|
|
125
|
+
them.
|
|
126
|
+
- The provider-neutral port receives only the media payload required by the
|
|
127
|
+
upstream contract.
|
|
128
|
+
- Chunk size, capture cadence, and audio format are negotiated by the
|
|
129
|
+
application and selected provider.
|
|
130
|
+
|
|
131
|
+
There is an unavoidable ambiguity if a process dies after the provider accepts
|
|
132
|
+
a fragment but before the application marks it forwarded. Most realtime
|
|
133
|
+
provider audio-append operations have no application idempotency key. Do not
|
|
134
|
+
claim exactly-once provider delivery; retain the durable recording and make
|
|
135
|
+
connection recovery explicit instead.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Invariant 4: Preserve Wire Order, Bound Every Queue
|
|
140
|
+
|
|
141
|
+
Inbound provider events and outbound client commands must be serialized per
|
|
142
|
+
connection. Concurrent callbacks may otherwise reorder transcript deltas,
|
|
143
|
+
tool calls, response cancellation, or audio commits.
|
|
144
|
+
|
|
145
|
+
Every queue also needs a finite capacity:
|
|
146
|
+
|
|
147
|
+
| Queue or buffer | Overflow policy |
|
|
148
|
+
| --- | --- |
|
|
149
|
+
| Client local queue | Stop capture or warn before storage exhaustion |
|
|
150
|
+
| Client-to-application frames | Apply socket backpressure and stop acknowledgement |
|
|
151
|
+
| Application persistence queue | Reject or pause the client; never grow without limit |
|
|
152
|
+
| Provider outbound queue | Fail the command with a retryability signal |
|
|
153
|
+
| Provider inbound queue | Close the connection when ordering can no longer be guaranteed |
|
|
154
|
+
| Metering queue | Close or degrade according to the application's billing safety policy |
|
|
155
|
+
| WebSocket buffered bytes | Reject additional writes until the socket drains |
|
|
156
|
+
|
|
157
|
+
`platform-intelligence` serializes provider events and enforces per-session
|
|
158
|
+
event and byte limits. These limits do not replace tenant quotas or client
|
|
159
|
+
gateway limits.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Invariant 5: Meter Through an Idempotent Application Port
|
|
164
|
+
|
|
165
|
+
Long-lived streams cannot rely on request interceptors for complete usage
|
|
166
|
+
accounting. Emit durable lifecycle and interval events through an application
|
|
167
|
+
port instead.
|
|
168
|
+
|
|
169
|
+
Each event must contain:
|
|
170
|
+
|
|
171
|
+
- a stable event ID;
|
|
172
|
+
- logical session and physical connection IDs;
|
|
173
|
+
- provider and model;
|
|
174
|
+
- occurrence time;
|
|
175
|
+
- bounded correlation metadata;
|
|
176
|
+
- event-specific interval, usage, or close data.
|
|
177
|
+
|
|
178
|
+
The adapter uses the event ID as a unique key and commits the usage event,
|
|
179
|
+
commercial ledger change, and AI audit record in one transaction.
|
|
180
|
+
|
|
181
|
+
```mermaid
|
|
182
|
+
flowchart LR
|
|
183
|
+
Event[Metering event with eventId]
|
|
184
|
+
Unique[Insert with unique eventId]
|
|
185
|
+
Debit[Debit credit ledger]
|
|
186
|
+
Audit[Append AI audit record]
|
|
187
|
+
Commit[Commit transaction]
|
|
188
|
+
|
|
189
|
+
Event --> Unique
|
|
190
|
+
Unique --> Debit
|
|
191
|
+
Debit --> Audit
|
|
192
|
+
Audit --> Commit
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Use provider-independent intervals for predictable commercial charging and
|
|
196
|
+
provider-reported token dimensions for reconciliation. Do not charge both
|
|
197
|
+
sources for the same work unless that is an explicit pricing rule.
|
|
198
|
+
|
|
199
|
+
The adapter should normally write to a local database transaction or outbox.
|
|
200
|
+
Calling a slow remote billing API directly increases queue pressure and makes
|
|
201
|
+
shutdown flushes unreliable.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Invariant 6: Reconnect Is a New Connection
|
|
206
|
+
|
|
207
|
+
Do not silently reconnect a stateful provider session. A replacement socket
|
|
208
|
+
does not necessarily contain the same model conversation, input buffer, tool
|
|
209
|
+
state, or response state.
|
|
210
|
+
|
|
211
|
+
```mermaid
|
|
212
|
+
stateDiagram-v2
|
|
213
|
+
[*] --> Idle
|
|
214
|
+
Idle --> Connecting: connect
|
|
215
|
+
Connecting --> Connected: socket open
|
|
216
|
+
Connecting --> Error: setup failure
|
|
217
|
+
Connected --> Closing: close
|
|
218
|
+
Connected --> Error: terminal transport failure
|
|
219
|
+
Closing --> Closed: close event or timeout
|
|
220
|
+
Error --> Closed: finalize
|
|
221
|
+
Closed --> [*]
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Recovery creates a new connection:
|
|
225
|
+
|
|
226
|
+
1. finalize and audit the failed connection;
|
|
227
|
+
2. keep the same logical session ID;
|
|
228
|
+
3. derive safe context from durable transcript and domain state;
|
|
229
|
+
4. create a replacement port with a new connection ID;
|
|
230
|
+
5. record the recovery relationship explicitly;
|
|
231
|
+
6. resume only unacknowledged application fragments according to provider
|
|
232
|
+
semantics.
|
|
233
|
+
|
|
234
|
+
Never claim lossless replay when the provider-neutral contract cannot restore
|
|
235
|
+
provider-native conversation state.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Invariant 7: Keep Provider Secrets and Contracts Upstream
|
|
240
|
+
|
|
241
|
+
The client must not receive permanent provider API keys. The application
|
|
242
|
+
gateway speaks an application-owned protocol; the platform adapter speaks the
|
|
243
|
+
provider protocol.
|
|
244
|
+
|
|
245
|
+
For realtime intelligence:
|
|
246
|
+
|
|
247
|
+
- provider-specific model creation and wire mapping go through Vercel AI SDK
|
|
248
|
+
provider packages;
|
|
249
|
+
- Archipel exposes normalized client and server event unions;
|
|
250
|
+
- a generic server WebSocket carries the provider configuration returned by
|
|
251
|
+
the AI SDK adapter;
|
|
252
|
+
- provider-native events remain available only as an audited `raw` escape
|
|
253
|
+
hatch.
|
|
254
|
+
|
|
255
|
+
This boundary allows the application to switch providers without rewriting
|
|
256
|
+
authentication, persistence, metering, or the client transport.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Invariant 8: Shutdown Is Part of Correctness
|
|
261
|
+
|
|
262
|
+
The owner of a long-lived connection must implement deterministic teardown:
|
|
263
|
+
|
|
264
|
+
1. reject or stop accepting new client input;
|
|
265
|
+
2. clear periodic timers;
|
|
266
|
+
3. close the upstream socket with a bounded timeout;
|
|
267
|
+
4. emit the final partial billing interval;
|
|
268
|
+
5. emit the connection-end event;
|
|
269
|
+
6. flush queued metering within the shutdown budget;
|
|
270
|
+
7. release the process-local ownership record.
|
|
271
|
+
|
|
272
|
+
The Nest application must enable shutdown hooks for `OnModuleDestroy` to run
|
|
273
|
+
on process signals.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Failure Policy
|
|
278
|
+
|
|
279
|
+
| Failure | Retry in place? | Required action |
|
|
280
|
+
| --- | --- | --- |
|
|
281
|
+
| Transient provider token creation | Yes, bounded | Retry with backoff before socket creation |
|
|
282
|
+
| Socket open timeout | No hidden reconnect | Fail connection attempt and report retryability |
|
|
283
|
+
| Outbound command failure | Caller decides | Keep client data unacknowledged when safe to retry |
|
|
284
|
+
| Malformed provider event | No | Report receive error; close if ordering is unsafe |
|
|
285
|
+
| Queue or byte limit exceeded | No | Apply backpressure or close with explicit reason |
|
|
286
|
+
| Metering adapter failure | Bounded retry | Persist through a durable local adapter; surface failure |
|
|
287
|
+
| Provider disconnect | No hidden reconnect | Finalize connection and start explicit recovery |
|
|
288
|
+
| Process shutdown | No | Drain and close within the configured timeout |
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Checklist
|
|
293
|
+
|
|
294
|
+
- Logical session and physical connection IDs are distinct.
|
|
295
|
+
- Exactly one process owns an active upstream connection.
|
|
296
|
+
- The client keeps unacknowledged fragments durably.
|
|
297
|
+
- The application persists fragments idempotently before acknowledgement.
|
|
298
|
+
- Streaming continues per fragment; there is no whole-session upload gate.
|
|
299
|
+
- Provider commands and events preserve per-connection order.
|
|
300
|
+
- Every queue, collection, timer, and byte buffer is bounded.
|
|
301
|
+
- Metering events have stable idempotency keys.
|
|
302
|
+
- Ledger debit and AI audit persistence share one transaction.
|
|
303
|
+
- Provider token data never reaches the client-facing protocol.
|
|
304
|
+
- Reconnect creates a visible new connection.
|
|
305
|
+
- Recovery claims only the context the provider contract can reconstruct.
|
|
306
|
+
- Shutdown closes sockets and flushes final metering.
|
|
307
|
+
|
|
308
|
+
See [AI Realtime Voice](../guides/ai-realtime-voice) for the concrete
|
|
309
|
+
`platform-intelligence` integration.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@breadstone/archipel-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.53",
|
|
4
4
|
"description": "MCP server providing Archipel platform knowledge - documentation, query patterns, and coding conventions - to AI development tools.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/main.js",
|