@driftengine/ai 3.61.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/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +103 -0
- package/dist/adapters/local.d.ts +29 -0
- package/dist/adapters/local.js +24 -0
- package/dist/adapters/proxy.d.ts +28 -0
- package/dist/adapters/proxy.js +138 -0
- package/dist/bridges/authority.d.ts +153 -0
- package/dist/bridges/authority.js +179 -0
- package/dist/bridges/navigation.d.ts +100 -0
- package/dist/bridges/navigation.js +139 -0
- package/dist/budget/budget.d.ts +34 -0
- package/dist/budget/budget.js +57 -0
- package/dist/command/apply.d.ts +24 -0
- package/dist/command/apply.js +40 -0
- package/dist/command/log.d.ts +55 -0
- package/dist/command/log.js +50 -0
- package/dist/context/assemble.d.ts +48 -0
- package/dist/context/assemble.js +55 -0
- package/dist/context/continuation.d.ts +14 -0
- package/dist/context/continuation.js +36 -0
- package/dist/describe/manifest.d.ts +70 -0
- package/dist/describe/manifest.js +99 -0
- package/dist/entities/context.d.ts +52 -0
- package/dist/entities/context.js +83 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.js +40 -0
- package/dist/policy/types.d.ts +55 -0
- package/dist/policy/types.js +26 -0
- package/dist/policy/utility.d.ts +18 -0
- package/dist/policy/utility.js +47 -0
- package/dist/provider/create.d.ts +16 -0
- package/dist/provider/create.js +57 -0
- package/dist/provider/latency.d.ts +27 -0
- package/dist/provider/latency.js +52 -0
- package/dist/provider/types.d.ts +90 -0
- package/dist/provider/types.js +8 -0
- package/dist/realtime/session.d.ts +35 -0
- package/dist/realtime/session.js +34 -0
- package/dist/session/agent.d.ts +217 -0
- package/dist/session/agent.js +506 -0
- package/dist/session/replay.d.ts +32 -0
- package/dist/session/replay.js +81 -0
- package/dist/session/states.d.ts +28 -0
- package/dist/session/states.js +33 -0
- package/dist/session/usage.d.ts +43 -0
- package/dist/session/usage.js +38 -0
- package/dist/testing/deterministic.d.ts +65 -0
- package/dist/testing/deterministic.js +150 -0
- package/dist/tools/policy.d.ts +47 -0
- package/dist/tools/policy.js +84 -0
- package/dist/tools/registry.d.ts +69 -0
- package/dist/tools/registry.js +75 -0
- package/dist/tools/validate.d.ts +24 -0
- package/dist/tools/validate.js +80 -0
- package/package.json +59 -0
- package/src/adapters/local.ts +64 -0
- package/src/adapters/proxy.ts +187 -0
- package/src/bridges/authority.ts +244 -0
- package/src/bridges/navigation.ts +207 -0
- package/src/budget/budget.ts +73 -0
- package/src/command/apply.ts +52 -0
- package/src/command/log.ts +81 -0
- package/src/context/assemble.ts +104 -0
- package/src/context/continuation.ts +39 -0
- package/src/describe/manifest.ts +148 -0
- package/src/entities/context.ts +112 -0
- package/src/index.ts +94 -0
- package/src/policy/types.ts +70 -0
- package/src/policy/utility.ts +53 -0
- package/src/provider/create.ts +70 -0
- package/src/provider/latency.ts +57 -0
- package/src/provider/types.ts +96 -0
- package/src/realtime/session.ts +63 -0
- package/src/session/agent.ts +622 -0
- package/src/session/replay.ts +96 -0
- package/src/session/states.ts +63 -0
- package/src/session/usage.ts +66 -0
- package/src/testing/deterministic.ts +204 -0
- package/src/tools/policy.ts +114 -0
- package/src/tools/registry.ts +122 -0
- package/src/tools/validate.ts +92 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The provider seam. Provider-specific concerns stay behind adapters.
|
|
3
|
+
*
|
|
4
|
+
* Capability is **declared rather than assumed**, so a session refuses an
|
|
5
|
+
* unsupported requirement early and in words instead of discovering it in
|
|
6
|
+
* production at whatever a failed request costs.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* What a provider says it can do.
|
|
11
|
+
*
|
|
12
|
+
* Declared by the adapter rather than probed, except where a probe is cheap and
|
|
13
|
+
* honest — `createLocalProvider` runs one, because a local model's availability is
|
|
14
|
+
* a property of the device rather than of the configuration.
|
|
15
|
+
*/
|
|
16
|
+
export interface AiProviderCapabilities {
|
|
17
|
+
readonly text: boolean;
|
|
18
|
+
readonly streamingText: boolean;
|
|
19
|
+
readonly structuredOutput: boolean;
|
|
20
|
+
readonly toolCalling: boolean;
|
|
21
|
+
readonly realtimeAudio: boolean;
|
|
22
|
+
readonly imageInput: boolean;
|
|
23
|
+
readonly local: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Context assembled for one request.
|
|
28
|
+
*
|
|
29
|
+
* Declared minimally here and widened where it is built. What the seam needs is
|
|
30
|
+
* the capture tick: a model must be able to know its snapshot may be stale, and a
|
|
31
|
+
* buffered agent widens that gap on purpose.
|
|
32
|
+
*/
|
|
33
|
+
export interface AssembledContextLike {
|
|
34
|
+
readonly capturedAtTick: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type AiEvent =
|
|
38
|
+
| { readonly kind: 'text'; readonly text: string }
|
|
39
|
+
| {
|
|
40
|
+
readonly kind: 'toolCall';
|
|
41
|
+
readonly callId: string;
|
|
42
|
+
readonly toolId: string;
|
|
43
|
+
readonly args: unknown;
|
|
44
|
+
}
|
|
45
|
+
| { readonly kind: 'usage'; readonly inputTokens: number; readonly outputTokens: number }
|
|
46
|
+
| {
|
|
47
|
+
readonly kind: 'done';
|
|
48
|
+
readonly reason: 'complete' | 'aborted' | 'error';
|
|
49
|
+
readonly message?: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export interface AiRequest {
|
|
53
|
+
readonly preamble: string;
|
|
54
|
+
readonly context: AssembledContextLike;
|
|
55
|
+
readonly toolIds: readonly string[];
|
|
56
|
+
readonly signal: AbortSignal;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface AiSessionOptions {
|
|
60
|
+
readonly model: string;
|
|
61
|
+
readonly systemPrompt?: string;
|
|
62
|
+
readonly maxOutputTokens?: number;
|
|
63
|
+
readonly temperature?: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface AiSession {
|
|
67
|
+
run(request: AiRequest): AsyncIterable<AiEvent>;
|
|
68
|
+
abort(reason?: string): void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface AiProvider {
|
|
72
|
+
readonly id: string;
|
|
73
|
+
readonly capabilities: AiProviderCapabilities;
|
|
74
|
+
createSession(options: AiSessionOptions): AiSession;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface AiProviderConfig {
|
|
78
|
+
readonly kind: 'proxy' | 'local' | 'deterministic';
|
|
79
|
+
readonly session: AiSessionOptions;
|
|
80
|
+
/**
|
|
81
|
+
* The provider itself, where the caller already has one.
|
|
82
|
+
*
|
|
83
|
+
* Adapters that must be constructed — a local model that has to probe the device —
|
|
84
|
+
* are built by their own factory and handed here, so this function does one job:
|
|
85
|
+
* comparing what is declared against what is required.
|
|
86
|
+
*/
|
|
87
|
+
readonly provider?: AiProvider;
|
|
88
|
+
/** Adapter-specific, and never a credential — see `adapters/proxy.ts`. */
|
|
89
|
+
readonly adapter?: Readonly<Record<string, unknown>>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface AiProviderResult {
|
|
93
|
+
readonly provider: AiProvider | null;
|
|
94
|
+
/** Always a sentence, on both paths. An empty reason is the silent no-op. */
|
|
95
|
+
readonly reason: string;
|
|
96
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { AiEvent, AiProvider, AiRequest, AiSession } from '../provider/types.ts';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A realtime transport, emitting the same events every other session emits.
|
|
5
|
+
*
|
|
6
|
+
* **Additive.** Nothing downstream branches on transport: the buffered loop, the floor,
|
|
7
|
+
* the admission guards and the command log all see the same `AiEvent` union they
|
|
8
|
+
* already see. A session with realtime configured still has exactly one request in
|
|
9
|
+
* flight, because the state machine does not know what a transport is.
|
|
10
|
+
*
|
|
11
|
+
* **Audio stays bridged, not coupled.** This module imports nothing from
|
|
12
|
+
* `@driftengine/audio`, and the package declares no dependency on it. A consumer wires
|
|
13
|
+
* its own microphone and speaker to whatever this yields, because the moment an AI
|
|
14
|
+
* package owned an audio graph it would be an AI package that knew what a mix was.
|
|
15
|
+
*/
|
|
16
|
+
export interface RealtimeOptions {
|
|
17
|
+
readonly model: string;
|
|
18
|
+
/** Frames a consumer pushes in. Text here, because audio is the consumer's to carry. */
|
|
19
|
+
readonly input?: AsyncIterable<string>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type RealtimeResult =
|
|
23
|
+
| { readonly session: AiSession; readonly reason: string }
|
|
24
|
+
| { readonly session: null; readonly reason: string };
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Open a realtime session, or refuse before connecting.
|
|
28
|
+
*
|
|
29
|
+
* Refused **before** any transport is opened, in the shape §32 requires of every other
|
|
30
|
+
* provider decision: a socket opened against a provider that cannot hold a realtime
|
|
31
|
+
* conversation is a socket that fails later and more expensively than a string
|
|
32
|
+
* comparison.
|
|
33
|
+
*/
|
|
34
|
+
export function createRealtimeSession(
|
|
35
|
+
provider: AiProvider,
|
|
36
|
+
options: RealtimeOptions,
|
|
37
|
+
): RealtimeResult {
|
|
38
|
+
if (!provider.capabilities.realtimeAudio) {
|
|
39
|
+
return {
|
|
40
|
+
session: null,
|
|
41
|
+
reason: `provider "${provider.id}" declares no realtime transport — a session cannot be opened against it`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const inner = provider.createSession({ model: options.model });
|
|
46
|
+
let disposed = false;
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
session: {
|
|
50
|
+
run(request: AiRequest): AsyncIterable<AiEvent> {
|
|
51
|
+
return inner.run(request);
|
|
52
|
+
},
|
|
53
|
+
abort(reason?: string): void {
|
|
54
|
+
/* A second disposal is a no-op rather than an error. Disposal races a scene
|
|
55
|
+
replacement and a hot reload, and both may reach the same session. */
|
|
56
|
+
if (disposed) return;
|
|
57
|
+
disposed = true;
|
|
58
|
+
inner.abort(reason ?? 'realtime session disposed');
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
reason: `realtime session open against "${provider.id}"`,
|
|
62
|
+
};
|
|
63
|
+
}
|