@jambonz/llm 0.1.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.
@@ -0,0 +1,162 @@
1
+ import { a as AdapterFactory, d as AuthKind, A as AuthSpec, l as LlmEvent, M as Message, L as LlmAdapter, c as ApiKeyAuth, g as ClientOptions, P as PromptRequest, n as ModelInfo, b as AdapterManifest } from '../types-D8rgMCbi.js';
2
+
3
+ /**
4
+ * Named scenarios the harness must be able to stage. Each scenario configures
5
+ * the vendor mock to produce a specific response the next time `stream()` is
6
+ * called. The kit calls `harness.mockScenario(name)` before running a test.
7
+ */
8
+ type ContractScenario =
9
+ /** 3+ text tokens then end('stop'). No tools. */
10
+ 'simple-stream'
11
+ /** A single tool call (no content) then end('tool'). */
12
+ | 'tool-call'
13
+ /** Content tokens, then a tool call, then end('tool'). */
14
+ | 'tool-call-after-tokens'
15
+ /** 10+ text tokens yielded slowly (>= 20ms apart) then end('stop'). */
16
+ | 'long-stream'
17
+ /**
18
+ * Stream that would produce a tool call, but with enough delay before the
19
+ * tool call arrives that the kit can fire an abort in the middle.
20
+ * Expected behavior: on abort, no toolCall event fires; end('aborted') is yielded.
21
+ */
22
+ | 'long-stream-with-pending-tool'
23
+ /** `listAvailableModels()` returns at least 2 models. */
24
+ | 'list-models';
25
+ /**
26
+ * A vendor-agnostic view of the most recent request the adapter sent upstream.
27
+ * The harness captures whatever the vendor wire actually contained and exposes
28
+ * a normalized view so the kit can assert on it without vendor knowledge.
29
+ */
30
+ interface CapturedRequest {
31
+ /** System prompt as the adapter forwarded it (top-level, injected-into-messages, or missing). */
32
+ system?: string;
33
+ /** Number of non-system messages forwarded. */
34
+ messageCount: number;
35
+ /** True if any message's vendorRaw contents appear to have influenced the wire request. */
36
+ vendorRawHonored: boolean;
37
+ }
38
+ /**
39
+ * Harness an adapter provides so the contract kit can run. Adapter authors
40
+ * implement this once for their adapter, then call `runContractTests(harness)`.
41
+ *
42
+ * The harness hides vendor-specific concerns (SDK mocking, wire format,
43
+ * credential shapes) behind a small uniform surface.
44
+ */
45
+ interface ContractHarness {
46
+ /** Machine-readable vendor id. Used in test descriptions only. */
47
+ vendor: string;
48
+ /** The factory under test. */
49
+ factory: AdapterFactory;
50
+ /**
51
+ * Return a valid AuthSpec for each `AuthKind` the adapter's manifest declares.
52
+ * Called once per declared kind during the "accepts declared auth kinds" check.
53
+ * Values need not be real credentials — mocks don't care.
54
+ */
55
+ authFor(kind: AuthKind): AuthSpec;
56
+ /**
57
+ * An AuthSpec that the adapter MUST reject via `init()`. Typically a kind the
58
+ * adapter does not accept. Return `null` if the adapter truly accepts every
59
+ * AuthKind (unusual — check #4 will be skipped).
60
+ */
61
+ unsupportedAuth: AuthSpec | null;
62
+ /**
63
+ * Configure the vendor mock for the named scenario. Called before each
64
+ * behavioral test. The next `stream()` or `listAvailableModels()` call will
65
+ * return the scenario's canned response.
66
+ */
67
+ mockScenario(scenario: ContractScenario): void | Promise<void>;
68
+ /**
69
+ * Clean up mocks between tests. Called in an `afterEach`. Safe to call even
70
+ * if no scenario is active.
71
+ */
72
+ cleanup(): void | Promise<void>;
73
+ /**
74
+ * Return a normalized view of the most recent wire request the adapter sent
75
+ * upstream, or null if no request has been made since the last cleanup().
76
+ */
77
+ getCapturedRequest(): CapturedRequest | null;
78
+ /** A model id in `knownModels` whose capabilities.tools is true. */
79
+ toolCapableModel: string;
80
+ /**
81
+ * A model id whose capabilities.tools is false, for check #16. Return null if
82
+ * the adapter has no non-tool-capable models in its manifest — the check is
83
+ * then skipped.
84
+ */
85
+ nonToolCapableModel: string | null;
86
+ /**
87
+ * Does this adapter emit `toolCallStart` events? If true, check #12
88
+ * (toolCallStart precedes toolCall) runs; if false, that check is skipped.
89
+ */
90
+ emitsToolCallStart: boolean;
91
+ /**
92
+ * Construct an assistant `Message` (with `vendorRaw` populated in the shape
93
+ * THIS adapter expects back on re-submission) given a `toolCall` event the
94
+ * adapter previously emitted. Used by checks #13 and #20 to round-trip a
95
+ * realistic history through a subsequent `stream()` call.
96
+ *
97
+ * Implementation tip: set `vendorRaw` to the full vendor-native assistant
98
+ * message — the same shape your adapter puts in history after emitting a
99
+ * tool call during streaming.
100
+ */
101
+ buildAssistantWithToolCall(tc: Extract<LlmEvent, {
102
+ type: 'toolCall';
103
+ }>): Message;
104
+ }
105
+
106
+ /**
107
+ * Run the 20 contract checks against a vendor adapter via its harness.
108
+ *
109
+ * Call at the top level of a test file; registers vitest `describe`/`it` blocks
110
+ * that exercise every aspect of the adapter contract. Adapters that pass this
111
+ * suite are merge-ready for the library.
112
+ *
113
+ * The suite registers the harness's factory in the library registry for the
114
+ * duration of the run; existing registrations are preserved after cleanup.
115
+ */
116
+ declare function runContractTests(harness: ContractHarness): void;
117
+
118
+ /**
119
+ * Shared mutable state between the harness and the fake adapter instance.
120
+ * The harness writes to it (via mockScenario/cleanup), the adapter reads it
121
+ * during stream() / listAvailableModels() to decide what to produce.
122
+ */
123
+ interface FakeState {
124
+ scenario: ContractScenario | null;
125
+ captured: CapturedRequest | null;
126
+ }
127
+ /**
128
+ * Reference fake adapter used by the test-kit to verify itself.
129
+ *
130
+ * Produces canned events for each `ContractScenario`. Does not talk to any
131
+ * real vendor. Used by `test/test-kit/self-check.test.ts` to prove that a
132
+ * correctly-behaving adapter passes all 20 contract checks.
133
+ *
134
+ * Anybody implementing a real adapter can read this as a minimal reference —
135
+ * it shows exactly what the library expects on the wire.
136
+ */
137
+ declare class FakeAdapter implements LlmAdapter<ApiKeyAuth> {
138
+ private readonly state;
139
+ readonly vendor: string;
140
+ readonly acceptedAuth: readonly ["apiKey"];
141
+ private initialized;
142
+ constructor(state: FakeState);
143
+ init(auth: ApiKeyAuth, _client?: ClientOptions): void;
144
+ stream(req: PromptRequest): AsyncIterable<LlmEvent>;
145
+ appendToolResult(history: Message[], toolCallId: string, result: unknown): Message[];
146
+ listAvailableModels(): Promise<ModelInfo[]>;
147
+ private ensureInitialized;
148
+ private capture;
149
+ }
150
+ declare const fakeManifest: AdapterManifest;
151
+ interface FakeHarness extends ContractHarness {
152
+ /** Expose the factory so callers can register if needed. */
153
+ factory: AdapterFactory;
154
+ }
155
+ /**
156
+ * Build a ContractHarness for the fake adapter. Used by the kit's self-check
157
+ * test. External contributors don't use this — they build their own harness
158
+ * against their adapter.
159
+ */
160
+ declare function createFakeHarness(): FakeHarness;
161
+
162
+ export { type CapturedRequest, type ContractHarness, type ContractScenario, FakeAdapter, type FakeHarness, createFakeHarness, fakeManifest, runContractTests };