@zhin.js/ai-provider 0.0.0-stage → 1.0.1
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 +21 -0
- package/README.md +21 -2
- package/lib/index.d.ts +26 -0
- package/lib/index.js +76 -0
- package/lib/index.js.map +1 -0
- package/lib/lazy-client.d.ts +13 -0
- package/lib/lazy-client.js +156 -0
- package/lib/lazy-client.js.map +1 -0
- package/lib/usage.d.ts +30 -0
- package/lib/usage.js +2 -0
- package/lib/usage.js.map +1 -0
- package/package.json +40 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 凉菜
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @zhin.js/ai-provider
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Plugin Runtime integration for the AI Provider contracts in `@zhin.js/ai/provider`.
|
|
4
|
+
|
|
5
|
+
Provider plugins publish all their definitions in one setup call:
|
|
6
|
+
`provideAiProviders(context.resources, [definition, anotherDefinition])`.
|
|
7
|
+
Repeated registration in the same Scope is rejected; declarations become immutable when setup seals.
|
|
8
|
+
Definitions keep their exact plugin owner. Host integrations resolve them from the operation's
|
|
9
|
+
held snapshot with `createSnapshotProviderResolver`; another plugin with the same driver name
|
|
10
|
+
cannot replace a saved Service's owner.
|
|
11
|
+
|
|
12
|
+
This package owns no model loop, accounts, credentials, network access or global registration.
|
|
13
|
+
An operation's `aiInferenceClientToken` contains only its already authorized `InferenceClient`.
|
|
14
|
+
SDKs remain optional dependencies of the actual Provider implementation.
|
|
15
|
+
|
|
16
|
+
Commands and Agent Tools receive independent operation clients through `context.use(aiInferenceClientToken)`.
|
|
17
|
+
The Host supplies the exact generation, identity and model graph; callers cannot pass an owner or account override.
|
|
18
|
+
Checking availability or acquiring the client does not open a model or consume quota. Streams start only when
|
|
19
|
+
consumed, and their owner closes escaped or unused runs when execution ends. A Tool never closes its parent turn.
|
|
20
|
+
|
|
21
|
+
Driver `profileSchema({service, model})` describes and validates the selected protocol's actual parameters.
|
|
22
|
+
Use one typed pure schema resolver for parsing and Console input metadata; keep Account secrets out of both.
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type PluginId, type RuntimeSnapshot, type Scope, type SnapshotLease, type SnapshotReader } from '@zhin.js/plugin-runtime';
|
|
2
|
+
import { type InferenceClient, type ProviderDefinition, type ProviderDriverResolver } from '@zhin.js/ai/provider';
|
|
3
|
+
export * from './lazy-client.js';
|
|
4
|
+
export * from './usage.js';
|
|
5
|
+
export interface ProvidedAiProvider {
|
|
6
|
+
readonly owner: PluginId;
|
|
7
|
+
readonly definition: ProviderDefinition<unknown, unknown>;
|
|
8
|
+
}
|
|
9
|
+
/** Declarations only; no accounts, mutable credentials or process-wide registry. */
|
|
10
|
+
export declare const aiProviderDefinitionsToken: import("@zhin.js/plugin-runtime").Token<readonly ProvidedAiProvider[]>;
|
|
11
|
+
/** Installed only on an actual operation with its already bound principal. */
|
|
12
|
+
export declare const aiInferenceClientToken: import("@zhin.js/plugin-runtime").Token<InferenceClient>;
|
|
13
|
+
export declare function provideAiProviders(resources: Scope, definitions: readonly ProviderDefinition<unknown, unknown>[]): void;
|
|
14
|
+
/** Pure projection of the supplied held snapshot; inherited declarations are not new owners. */
|
|
15
|
+
export declare function listSnapshotAiProviders(snapshot: RuntimeSnapshot): readonly ProvidedAiProvider[];
|
|
16
|
+
export declare function describeSnapshotAiProvider(input: {
|
|
17
|
+
readonly snapshot: RuntimeSnapshot;
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly owner?: string;
|
|
20
|
+
}): ProvidedAiProvider;
|
|
21
|
+
export interface SnapshotProviderResolverOptions {
|
|
22
|
+
readonly snapshots: SnapshotReader;
|
|
23
|
+
/** The held operation generation, never a lookup of the latest snapshot. */
|
|
24
|
+
readonly lease: SnapshotLease;
|
|
25
|
+
}
|
|
26
|
+
export declare function createSnapshotProviderResolver(options: SnapshotProviderResolverOptions): ProviderDriverResolver;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createToken } from '@zhin.js/plugin-runtime';
|
|
2
|
+
import { ProviderError } from '@zhin.js/ai/provider';
|
|
3
|
+
export * from './lazy-client.js';
|
|
4
|
+
export * from './usage.js';
|
|
5
|
+
/** Declarations only; no accounts, mutable credentials or process-wide registry. */
|
|
6
|
+
export const aiProviderDefinitionsToken = createToken('zhin.ai.provider-definitions');
|
|
7
|
+
/** Installed only on an actual operation with its already bound principal. */
|
|
8
|
+
export const aiInferenceClientToken = createToken('zhin.ai.inference-client');
|
|
9
|
+
export function provideAiProviders(resources, definitions) {
|
|
10
|
+
const names = new Set();
|
|
11
|
+
const entries = definitions.map(definition => {
|
|
12
|
+
if (!definition.id || names.has(definition.id))
|
|
13
|
+
throw new Error('Duplicate or empty AI Provider definition');
|
|
14
|
+
names.add(definition.id);
|
|
15
|
+
return Object.freeze({ owner: resources.owner, definition });
|
|
16
|
+
});
|
|
17
|
+
resources.provide(aiProviderDefinitionsToken, Object.freeze(entries));
|
|
18
|
+
}
|
|
19
|
+
/** Pure projection of the supplied held snapshot; inherited declarations are not new owners. */
|
|
20
|
+
export function listSnapshotAiProviders(snapshot) {
|
|
21
|
+
const result = [];
|
|
22
|
+
for (const [owner, resources] of snapshot.resources) {
|
|
23
|
+
if (!snapshot.tree.has(owner))
|
|
24
|
+
continue;
|
|
25
|
+
const entries = resources.get(aiProviderDefinitionsToken.id);
|
|
26
|
+
for (const entry of entries ?? [])
|
|
27
|
+
if (entry.owner === owner)
|
|
28
|
+
result.push(entry);
|
|
29
|
+
}
|
|
30
|
+
return Object.freeze(result);
|
|
31
|
+
}
|
|
32
|
+
export function describeSnapshotAiProvider(input) {
|
|
33
|
+
const matches = listSnapshotAiProviders(input.snapshot).filter(entry => entry.definition.id === input.id && (input.owner === undefined || entry.owner === input.owner));
|
|
34
|
+
const matched = matches[0];
|
|
35
|
+
if (!matched)
|
|
36
|
+
throw new ProviderError('driver-unavailable');
|
|
37
|
+
if (matches.length !== 1)
|
|
38
|
+
throw new Error('AI Provider driver name is ambiguous; select an exact owner');
|
|
39
|
+
return matched;
|
|
40
|
+
}
|
|
41
|
+
export function createSnapshotProviderResolver(options) {
|
|
42
|
+
return {
|
|
43
|
+
async acquire({ service, signal }) {
|
|
44
|
+
signal.throwIfAborted();
|
|
45
|
+
const lease = options.snapshots.retain(options.lease);
|
|
46
|
+
try {
|
|
47
|
+
const snapshot = lease.value;
|
|
48
|
+
const owner = service.driver.owner;
|
|
49
|
+
if (!snapshot.tree.has(owner))
|
|
50
|
+
throw new ProviderError('driver-unavailable');
|
|
51
|
+
const entries = snapshot.resources.get(owner)?.get(aiProviderDefinitionsToken.id);
|
|
52
|
+
const provided = entries?.find(entry => entry.owner === owner && entry.definition.id === service.driver.id);
|
|
53
|
+
if (!provided)
|
|
54
|
+
throw new ProviderError('driver-unavailable');
|
|
55
|
+
if (provided.definition.contractVersion !== service.driver.contractVersion)
|
|
56
|
+
throw new ProviderError('driver-contract-mismatch');
|
|
57
|
+
let released = false;
|
|
58
|
+
return {
|
|
59
|
+
definition: provided.definition,
|
|
60
|
+
reference: Object.freeze({ ...service.driver }),
|
|
61
|
+
release() {
|
|
62
|
+
if (released)
|
|
63
|
+
return;
|
|
64
|
+
released = true;
|
|
65
|
+
lease.release();
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
lease.release();
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { createToken, type PluginId, type RuntimeSnapshot, type Scope, type SnapshotLease, type SnapshotReader } from '@zhin.js/plugin-runtime';\nimport { ProviderError, type InferenceClient, type ProviderDefinition, type ProviderDriverResolver } from '@zhin.js/ai/provider';\nexport * from './lazy-client.js';\nexport * from './usage.js';\n\nexport interface ProvidedAiProvider {\n readonly owner: PluginId;\n readonly definition: ProviderDefinition<unknown, unknown>;\n}\n\n/** Declarations only; no accounts, mutable credentials or process-wide registry. */\nexport const aiProviderDefinitionsToken = createToken<readonly ProvidedAiProvider[]>('zhin.ai.provider-definitions');\n\n/** Installed only on an actual operation with its already bound principal. */\nexport const aiInferenceClientToken = createToken<InferenceClient>('zhin.ai.inference-client');\n\nexport function provideAiProviders(\n resources: Scope,\n definitions: readonly ProviderDefinition<unknown, unknown>[],\n): void {\n const names = new Set<string>();\n const entries = definitions.map(definition => {\n if (!definition.id || names.has(definition.id)) throw new Error('Duplicate or empty AI Provider definition');\n names.add(definition.id);\n return Object.freeze({ owner: resources.owner, definition });\n });\n resources.provide(aiProviderDefinitionsToken, Object.freeze(entries));\n}\n\n/** Pure projection of the supplied held snapshot; inherited declarations are not new owners. */\nexport function listSnapshotAiProviders(snapshot: RuntimeSnapshot): readonly ProvidedAiProvider[] {\n const result: ProvidedAiProvider[] = [];\n for (const [owner, resources] of snapshot.resources) {\n if (!snapshot.tree.has(owner)) continue;\n const entries = resources.get(aiProviderDefinitionsToken.id) as readonly ProvidedAiProvider[] | undefined;\n for (const entry of entries ?? []) if (entry.owner === owner) result.push(entry);\n }\n return Object.freeze(result);\n}\n\nexport function describeSnapshotAiProvider(input: {\n readonly snapshot: RuntimeSnapshot;\n readonly id: string;\n readonly owner?: string;\n}): ProvidedAiProvider {\n const matches = listSnapshotAiProviders(input.snapshot).filter(entry =>\n entry.definition.id === input.id && (input.owner === undefined || entry.owner === input.owner));\n const matched = matches[0];\n if (!matched) throw new ProviderError('driver-unavailable');\n if (matches.length !== 1) throw new Error('AI Provider driver name is ambiguous; select an exact owner');\n return matched;\n}\n\nexport interface SnapshotProviderResolverOptions {\n readonly snapshots: SnapshotReader;\n /** The held operation generation, never a lookup of the latest snapshot. */\n readonly lease: SnapshotLease;\n}\n\nexport function createSnapshotProviderResolver(options: SnapshotProviderResolverOptions): ProviderDriverResolver {\n return {\n async acquire({ service, signal }) {\n signal.throwIfAborted();\n const lease = options.snapshots.retain(options.lease);\n try {\n const snapshot = lease.value;\n const owner = service.driver.owner as PluginId;\n if (!snapshot.tree.has(owner)) throw new ProviderError('driver-unavailable');\n const entries = snapshot.resources.get(owner)?.get(aiProviderDefinitionsToken.id) as readonly ProvidedAiProvider[] | undefined;\n const provided = entries?.find(entry => entry.owner === owner && entry.definition.id === service.driver.id);\n if (!provided) throw new ProviderError('driver-unavailable');\n if (provided.definition.contractVersion !== service.driver.contractVersion) throw new ProviderError('driver-contract-mismatch');\n let released = false;\n return {\n definition: provided.definition,\n reference: Object.freeze({ ...service.driver }),\n release() {\n if (released) return;\n released = true;\n lease.release();\n },\n };\n } catch (error) {\n lease.release();\n throw error;\n }\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type InferenceClient } from '@zhin.js/ai/provider';
|
|
2
|
+
import type { InferenceUsageAccounting } from './usage.js';
|
|
3
|
+
export interface LazyInferenceClientOptions {
|
|
4
|
+
readonly signal: AbortSignal;
|
|
5
|
+
/** Host closure owns the exact lease, identity and graph capture; callers supply none of them. */
|
|
6
|
+
readonly open: (input: Readonly<{
|
|
7
|
+
signal: AbortSignal;
|
|
8
|
+
}>) => Promise<InferenceClient>;
|
|
9
|
+
readonly accounting?: InferenceUsageAccounting;
|
|
10
|
+
readonly onCleanupError?: (error: unknown) => void;
|
|
11
|
+
}
|
|
12
|
+
/** One operation's lazy client. Returning it from execute does not transfer its lifetime. */
|
|
13
|
+
export declare function createLazyInferenceClient(options: LazyInferenceClientOptions): InferenceClient;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { assistantText } from '@zhin.js/ai';
|
|
2
|
+
import { OwnedLanguageRun, ProviderError } from '@zhin.js/ai/provider';
|
|
3
|
+
function usage(message) {
|
|
4
|
+
const reported = message.usage.reported;
|
|
5
|
+
const total = reported ? reported.totalTokens === true || reported.input === true && reported.output === true
|
|
6
|
+
? message.usage.totalTokens : undefined : message.usage.totalTokens > 0 ? message.usage.totalTokens : undefined;
|
|
7
|
+
return { ...(total !== undefined ? { totalTokens: total } : {}), text: assistantText(message) };
|
|
8
|
+
}
|
|
9
|
+
/** One operation's lazy client. Returning it from execute does not transfer its lifetime. */
|
|
10
|
+
export function createLazyInferenceClient(options) {
|
|
11
|
+
const controller = new AbortController();
|
|
12
|
+
const signal = AbortSignal.any([controller.signal, options.signal]);
|
|
13
|
+
const pending = new Set(), runs = new Set();
|
|
14
|
+
let opening, closing, underlyingClose;
|
|
15
|
+
let closed = false;
|
|
16
|
+
const report = (error) => { try {
|
|
17
|
+
options.onCleanupError?.(error);
|
|
18
|
+
}
|
|
19
|
+
catch { /* diagnostics are not business results */ } };
|
|
20
|
+
const dispose = (client) => underlyingClose ??= Promise.resolve().then(() => client.close()).catch(report);
|
|
21
|
+
function assertOpen() {
|
|
22
|
+
if (closed)
|
|
23
|
+
throw new ProviderError('operation-closed');
|
|
24
|
+
signal.throwIfAborted();
|
|
25
|
+
}
|
|
26
|
+
function get() {
|
|
27
|
+
assertOpen();
|
|
28
|
+
return opening ??= Promise.resolve().then(() => { assertOpen(); return options.open({ signal }); }).then(async (client) => {
|
|
29
|
+
if (closed || signal.aborted) {
|
|
30
|
+
await dispose(client);
|
|
31
|
+
throw new ProviderError('operation-closed');
|
|
32
|
+
}
|
|
33
|
+
return client;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function track(promise) {
|
|
37
|
+
pending.add(promise);
|
|
38
|
+
void promise.then(() => pending.delete(promise), () => pending.delete(promise));
|
|
39
|
+
return promise;
|
|
40
|
+
}
|
|
41
|
+
async function invoke(request, execute, outcome) {
|
|
42
|
+
assertOpen();
|
|
43
|
+
const invocation = options.accounting?.begin(request);
|
|
44
|
+
try {
|
|
45
|
+
const operation = async () => execute(await get());
|
|
46
|
+
const result = await (invocation ? invocation.run(operation) : operation());
|
|
47
|
+
try {
|
|
48
|
+
invocation?.finish(outcome(result));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
report(error);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
try {
|
|
57
|
+
invocation?.close();
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
report(error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function close() {
|
|
65
|
+
if (closing)
|
|
66
|
+
return closing;
|
|
67
|
+
closed = true;
|
|
68
|
+
options.signal.removeEventListener('abort', stop);
|
|
69
|
+
controller.abort(new ProviderError('operation-closed'));
|
|
70
|
+
return closing = (async () => {
|
|
71
|
+
await Promise.allSettled([...runs].map(run => run.close()));
|
|
72
|
+
await Promise.allSettled([...pending]);
|
|
73
|
+
if (opening)
|
|
74
|
+
await opening.then(dispose, () => undefined);
|
|
75
|
+
})();
|
|
76
|
+
}
|
|
77
|
+
const stop = () => { void close().catch(report); };
|
|
78
|
+
options.signal.addEventListener('abort', stop, { once: true });
|
|
79
|
+
if (options.signal.aborted)
|
|
80
|
+
stop();
|
|
81
|
+
const client = {
|
|
82
|
+
list(input) { return track((async () => (await get()).list(input))()); },
|
|
83
|
+
generate(input) {
|
|
84
|
+
return track(invoke({ kind: 'language', request: input.request }, underlying => underlying.generate({ ...input,
|
|
85
|
+
signal: input.signal ? AbortSignal.any([signal, input.signal]) : signal }), usage));
|
|
86
|
+
},
|
|
87
|
+
evaluate(input) {
|
|
88
|
+
return track(invoke({ kind: 'decision', state: input.state, questions: input.questions }, underlying => underlying.evaluate({ ...input,
|
|
89
|
+
signal: input.signal ? AbortSignal.any([signal, input.signal]) : signal }), result => ({ totalTokens: result.usage.inputTokens + result.usage.outputTokens })));
|
|
90
|
+
},
|
|
91
|
+
generateImage(input) {
|
|
92
|
+
return track(invoke({ kind: 'image', request: input.request }, underlying => underlying.generateImage({ ...input,
|
|
93
|
+
signal: input.signal ? AbortSignal.any([signal, input.signal]) : signal }), () => ({})));
|
|
94
|
+
},
|
|
95
|
+
async stream(input) {
|
|
96
|
+
assertOpen();
|
|
97
|
+
const streamController = new AbortController();
|
|
98
|
+
const streamSignal = AbortSignal.any([signal, streamController.signal, ...(input.signal ? [input.signal] : [])]);
|
|
99
|
+
let invocation, source, released;
|
|
100
|
+
const cancel = () => streamController.abort(streamSignal.reason);
|
|
101
|
+
const release = () => released ??= (async () => {
|
|
102
|
+
runs.delete(run);
|
|
103
|
+
streamSignal.removeEventListener('abort', cancel);
|
|
104
|
+
try {
|
|
105
|
+
await source?.close();
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
report(error);
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
invocation?.close();
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
report(error);
|
|
115
|
+
}
|
|
116
|
+
})();
|
|
117
|
+
async function* events() {
|
|
118
|
+
assertOpen();
|
|
119
|
+
streamSignal.throwIfAborted();
|
|
120
|
+
invocation = options.accounting?.begin({ kind: 'language', request: input.request });
|
|
121
|
+
const within = (operation) => invocation ? invocation.run(operation) : operation();
|
|
122
|
+
try {
|
|
123
|
+
source = await within(async () => (await get()).stream({ ...input, signal: streamSignal }));
|
|
124
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
125
|
+
for (;;) {
|
|
126
|
+
const next = await within(() => iterator.next());
|
|
127
|
+
if (next.done)
|
|
128
|
+
return;
|
|
129
|
+
if (next.value.type === 'done' && next.value.message) {
|
|
130
|
+
try {
|
|
131
|
+
invocation?.finish(usage(next.value.message));
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
report(error);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
yield next.value;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
await release();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const run = new OwnedLanguageRun({ source: events(), controller: streamController, release, project: value => value, onCleanupError: report });
|
|
145
|
+
runs.add(run);
|
|
146
|
+
streamSignal.addEventListener('abort', cancel, { once: true });
|
|
147
|
+
if (streamSignal.aborted)
|
|
148
|
+
cancel();
|
|
149
|
+
return run;
|
|
150
|
+
},
|
|
151
|
+
close,
|
|
152
|
+
[Symbol.asyncDispose]: close,
|
|
153
|
+
};
|
|
154
|
+
return Object.freeze(client);
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=lazy-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy-client.js","sourceRoot":"","sources":["../src/lazy-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAoD,MAAM,aAAa,CAAC;AAC9F,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAA0C,MAAM,sBAAsB,CAAC;AAU/G,SAAS,KAAK,CAAC,OAAyB;IACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC;IACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,KAAK,IAAI,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAC,MAAM,KAAK,IAAI;QAC3G,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;IAClH,OAAO,EAAE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;AAClG,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,yBAAyB,CAAC,OAAmC;IAC3E,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,EAAE,IAAI,GAAG,IAAI,GAAG,EAAe,CAAC;IAC3E,IAAI,OAA6C,EAAE,OAAkC,EAAE,eAA0C,CAAC;IAClI,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,MAAM,MAAM,GAAG,CAAC,KAAc,EAAE,EAAE,GAAG,IAAI,CAAC;QAAC,OAAO,CAAC,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,0CAA0C,CAAC,CAAC,CAAC,CAAC,CAAC;IACrI,MAAM,OAAO,GAAG,CAAC,MAAuB,EAAE,EAAE,CAAC,eAAe,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5H,SAAS,UAAU;QACjB,IAAI,MAAM;YAAE,MAAM,IAAI,aAAa,CAAC,kBAAkB,CAAC,CAAC;QACxD,MAAM,CAAC,cAAc,EAAE,CAAC;IAC1B,CAAC;IACD,SAAS,GAAG;QACV,UAAU,EAAE,CAAC;QACb,OAAO,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,EAAE,CAAC,CAAC,OAAO,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAC,MAAM,EAAC,EAAE;YACtH,IAAI,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBAAC,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;gBAAC,MAAM,IAAI,aAAa,CAAC,kBAAkB,CAAC,CAAC;YAAC,CAAC;YACrG,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;IACD,SAAS,KAAK,CAAI,OAAmB;QACnC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACtG,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,KAAK,UAAU,MAAM,CAAI,OAA8B,EAAE,OAAgD,EAAE,OAA6C;QACtJ,UAAU,EAAE,CAAC;QACb,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACtD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;YACnD,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;YAC5E,IAAI,CAAC;gBAAC,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAAC,CAAC;YAC7E,OAAO,MAAM,CAAC;QAChB,CAAC;gBAAS,CAAC;YAAC,IAAI,CAAC;gBAAC,UAAU,EAAE,KAAK,EAAE,CAAC;YAAC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAAC,CAAC;QAAC,CAAC;IAC7E,CAAC;IACD,KAAK,UAAU,KAAK;QAClB,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAC5B,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACjE,UAAU,CAAC,KAAK,CAAC,IAAI,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC;QACxD,OAAO,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;YAC3B,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAC5D,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;YACvC,IAAI,OAAO;gBAAE,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5D,CAAC,CAAC,EAAE,CAAC;IACP,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,EAAE,GAAG,KAAK,KAAK,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO;QAAE,IAAI,EAAE,CAAC;IACnC,MAAM,MAAM,GAAoB;QAC9B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxE,QAAQ,CAAC,KAAK;YACZ,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,GAAG,KAAK;gBAC5G,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QACxF,CAAC;QACD,QAAQ,CAAC,KAAK;YACZ,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,GAAG,KAAK;gBACpI,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;QACpK,CAAC;QACD,aAAa,CAAC,KAAK;YACjB,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,GAAG,KAAK;gBAC9G,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7F,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,KAAK;YAChB,UAAU,EAAE,CAAC;YACb,MAAM,gBAAgB,GAAG,IAAI,eAAe,EAAE,CAAC;YAC/C,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACjH,IAAI,UAAgD,EAAE,MAA+B,EAAE,QAAmC,CAAC;YAC3H,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YACjE,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,QAAQ,KAAK,CAAC,KAAK,IAAI,EAAE;gBAC7C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjB,YAAY,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAClD,IAAI,CAAC;oBAAC,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC;gBAAC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAAC,CAAC;gBAC/D,IAAI,CAAC;oBAAC,UAAU,EAAE,KAAK,EAAE,CAAC;gBAAC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAAC,CAAC;YAC/D,CAAC,CAAC,EAAE,CAAC;YACL,KAAK,SAAS,CAAC,CAAC,MAAM;gBACpB,UAAU,EAAE,CAAC;gBAAC,YAAY,CAAC,cAAc,EAAE,CAAC;gBAC5C,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBACrF,MAAM,MAAM,GAAG,CAAI,SAA2B,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;gBACxG,IAAI,CAAC;oBACH,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;oBAC5F,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;oBAChD,SAAS,CAAC;wBACR,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;wBACjD,IAAI,IAAI,CAAC,IAAI;4BAAE,OAAO;wBACtB,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;4BACrD,IAAI,CAAC;gCAAC,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;4BAAC,CAAC;4BAAC,OAAO,KAAK,EAAE,CAAC;gCAAC,MAAM,CAAC,KAAK,CAAC,CAAC;4BAAC,CAAC;wBACzF,CAAC;wBACD,MAAM,IAAI,CAAC,KAAK,CAAC;oBACnB,CAAC;gBACH,CAAC;wBAAS,CAAC;oBAAC,MAAM,OAAO,EAAE,CAAC;gBAAC,CAAC;YAChC,CAAC;YACD,MAAM,GAAG,GAAG,IAAI,gBAAgB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/I,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/D,IAAI,YAAY,CAAC,OAAO;gBAAE,MAAM,EAAE,CAAC;YACnC,OAAO,GAAG,CAAC;QACb,CAAC;QACD,KAAK;QACL,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,KAAK;KAC7B,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC","sourcesContent":["import { assistantText, type AssistantMessage, type AssistantStreamEvent } from '@zhin.js/ai';\nimport { OwnedLanguageRun, ProviderError, type InferenceClient, type LanguageRun } from '@zhin.js/ai/provider';\nimport type { InferenceUsageAccounting, InferenceUsageInvocation, InferenceUsageOutcome, InferenceUsageRequest } from './usage.js';\n\nexport interface LazyInferenceClientOptions {\n readonly signal: AbortSignal;\n /** Host closure owns the exact lease, identity and graph capture; callers supply none of them. */\n readonly open: (input: Readonly<{ signal: AbortSignal }>) => Promise<InferenceClient>;\n readonly accounting?: InferenceUsageAccounting;\n readonly onCleanupError?: (error: unknown) => void;\n}\nfunction usage(message: AssistantMessage): InferenceUsageOutcome {\n const reported = message.usage.reported;\n const total = reported ? reported.totalTokens === true || reported.input === true && reported.output === true\n ? message.usage.totalTokens : undefined : message.usage.totalTokens > 0 ? message.usage.totalTokens : undefined;\n return { ...(total !== undefined ? { totalTokens: total } : {}), text: assistantText(message) };\n}\n\n/** One operation's lazy client. Returning it from execute does not transfer its lifetime. */\nexport function createLazyInferenceClient(options: LazyInferenceClientOptions): InferenceClient {\n const controller = new AbortController();\n const signal = AbortSignal.any([controller.signal, options.signal]);\n const pending = new Set<Promise<unknown>>(), runs = new Set<LanguageRun>();\n let opening: Promise<InferenceClient> | undefined, closing: Promise<void> | undefined, underlyingClose: Promise<void> | undefined;\n let closed = false;\n const report = (error: unknown) => { try { options.onCleanupError?.(error); } catch { /* diagnostics are not business results */ } };\n const dispose = (client: InferenceClient) => underlyingClose ??= Promise.resolve().then(() => client.close()).catch(report);\n function assertOpen() {\n if (closed) throw new ProviderError('operation-closed');\n signal.throwIfAborted();\n }\n function get(): Promise<InferenceClient> {\n assertOpen();\n return opening ??= Promise.resolve().then(() => { assertOpen(); return options.open({ signal }); }).then(async client => {\n if (closed || signal.aborted) { await dispose(client); throw new ProviderError('operation-closed'); }\n return client;\n });\n }\n function track<T>(promise: Promise<T>): Promise<T> {\n pending.add(promise); void promise.then(() => pending.delete(promise), () => pending.delete(promise));\n return promise;\n }\n async function invoke<T>(request: InferenceUsageRequest, execute: (client: InferenceClient) => Promise<T>, outcome: (result: T) => InferenceUsageOutcome): Promise<T> {\n assertOpen();\n const invocation = options.accounting?.begin(request);\n try {\n const operation = async () => execute(await get());\n const result = await (invocation ? invocation.run(operation) : operation());\n try { invocation?.finish(outcome(result)); } catch (error) { report(error); }\n return result;\n } finally { try { invocation?.close(); } catch (error) { report(error); } }\n }\n async function close(): Promise<void> {\n if (closing) return closing;\n closed = true; options.signal.removeEventListener('abort', stop);\n controller.abort(new ProviderError('operation-closed'));\n return closing = (async () => {\n await Promise.allSettled([...runs].map(run => run.close()));\n await Promise.allSettled([...pending]);\n if (opening) await opening.then(dispose, () => undefined);\n })();\n }\n const stop = () => { void close().catch(report); };\n options.signal.addEventListener('abort', stop, { once: true });\n if (options.signal.aborted) stop();\n const client: InferenceClient = {\n list(input) { return track((async () => (await get()).list(input))()); },\n generate(input) {\n return track(invoke({ kind: 'language', request: input.request }, underlying => underlying.generate({ ...input,\n signal: input.signal ? AbortSignal.any([signal, input.signal]) : signal }), usage));\n },\n evaluate(input) {\n return track(invoke({ kind: 'decision', state: input.state, questions: input.questions }, underlying => underlying.evaluate({ ...input,\n signal: input.signal ? AbortSignal.any([signal, input.signal]) : signal }), result => ({ totalTokens: result.usage.inputTokens + result.usage.outputTokens })));\n },\n generateImage(input) {\n return track(invoke({ kind: 'image', request: input.request }, underlying => underlying.generateImage({ ...input,\n signal: input.signal ? AbortSignal.any([signal, input.signal]) : signal }), () => ({})));\n },\n async stream(input) {\n assertOpen();\n const streamController = new AbortController();\n const streamSignal = AbortSignal.any([signal, streamController.signal, ...(input.signal ? [input.signal] : [])]);\n let invocation: InferenceUsageInvocation | undefined, source: LanguageRun | undefined, released: Promise<void> | undefined;\n const cancel = () => streamController.abort(streamSignal.reason);\n const release = () => released ??= (async () => {\n runs.delete(run);\n streamSignal.removeEventListener('abort', cancel);\n try { await source?.close(); } catch (error) { report(error); }\n try { invocation?.close(); } catch (error) { report(error); }\n })();\n async function* events(): AsyncGenerator<AssistantStreamEvent> {\n assertOpen(); streamSignal.throwIfAborted();\n invocation = options.accounting?.begin({ kind: 'language', request: input.request });\n const within = <T>(operation: () => Promise<T>) => invocation ? invocation.run(operation) : operation();\n try {\n source = await within(async () => (await get()).stream({ ...input, signal: streamSignal }));\n const iterator = source[Symbol.asyncIterator]();\n for (;;) {\n const next = await within(() => iterator.next());\n if (next.done) return;\n if (next.value.type === 'done' && next.value.message) {\n try { invocation?.finish(usage(next.value.message)); } catch (error) { report(error); }\n }\n yield next.value;\n }\n } finally { await release(); }\n }\n const run = new OwnedLanguageRun({ source: events(), controller: streamController, release, project: value => value, onCleanupError: report });\n runs.add(run);\n streamSignal.addEventListener('abort', cancel, { once: true });\n if (streamSignal.aborted) cancel();\n return run;\n },\n close,\n [Symbol.asyncDispose]: close,\n };\n return Object.freeze(client);\n}\n"]}
|
package/lib/usage.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DecisionQuestions, JsonValue, GenerateImageInput, LanguageRequest } from '@zhin.js/ai/provider';
|
|
2
|
+
/** Semantic input only. Account identity and quota subjects are supplied privately by Host. */
|
|
3
|
+
export type InferenceUsageRequest = Readonly<{
|
|
4
|
+
kind: 'language';
|
|
5
|
+
request: LanguageRequest;
|
|
6
|
+
}> | Readonly<{
|
|
7
|
+
kind: 'decision';
|
|
8
|
+
state: JsonValue;
|
|
9
|
+
questions: DecisionQuestions;
|
|
10
|
+
}> | Readonly<{
|
|
11
|
+
kind: 'image';
|
|
12
|
+
request: GenerateImageInput['request'];
|
|
13
|
+
}>;
|
|
14
|
+
export interface InferenceUsageOutcome {
|
|
15
|
+
/** Absent means unknown; zero is a reported zero, never an implicit estimate. */
|
|
16
|
+
readonly totalTokens?: number;
|
|
17
|
+
readonly text?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface InferenceUsageInvocation {
|
|
20
|
+
/** Preserve this call's private attribution through actual asynchronous transport work. */
|
|
21
|
+
run<T>(execute: () => Promise<T>): Promise<T>;
|
|
22
|
+
finish(outcome: InferenceUsageOutcome): void;
|
|
23
|
+
close(): void;
|
|
24
|
+
}
|
|
25
|
+
export interface InferenceUsageAccounting {
|
|
26
|
+
/** Admission may deny. Merely constructing a lazy client/run never calls this. */
|
|
27
|
+
begin(input: InferenceUsageRequest): InferenceUsageInvocation;
|
|
28
|
+
/** Called immediately before the actual inference transport submits, not for OAuth or catalogues. */
|
|
29
|
+
submitted(): void;
|
|
30
|
+
}
|
package/lib/usage.js
ADDED
package/lib/usage.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"","sourcesContent":["import type { DecisionQuestions, JsonValue, GenerateImageInput, LanguageRequest } from '@zhin.js/ai/provider';\n\n/** Semantic input only. Account identity and quota subjects are supplied privately by Host. */\nexport type InferenceUsageRequest =\n | Readonly<{ kind: 'language'; request: LanguageRequest }>\n | Readonly<{ kind: 'decision'; state: JsonValue; questions: DecisionQuestions }>\n | Readonly<{ kind: 'image'; request: GenerateImageInput['request'] }>;\nexport interface InferenceUsageOutcome {\n /** Absent means unknown; zero is a reported zero, never an implicit estimate. */\n readonly totalTokens?: number;\n readonly text?: string;\n}\nexport interface InferenceUsageInvocation {\n /** Preserve this call's private attribution through actual asynchronous transport work. */\n run<T>(execute: () => Promise<T>): Promise<T>;\n finish(outcome: InferenceUsageOutcome): void;\n close(): void;\n}\nexport interface InferenceUsageAccounting {\n /** Admission may deny. Merely constructing a lazy client/run never calls this. */\n begin(input: InferenceUsageRequest): InferenceUsageInvocation;\n /** Called immediately before the actual inference transport submits, not for OAuth or catalogues. */\n submitted(): void;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/ai-provider",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Owner-scoped AI Provider registration for Zhin Plugin Runtime",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./lib/index.js",
|
|
7
|
+
"types": "./lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"import": "./lib/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"lib"
|
|
16
|
+
],
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@zhin.js/ai": "1.1.51",
|
|
19
|
+
"@zhin.js/plugin-runtime": "1.1.20"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^26.1.2",
|
|
23
|
+
"typescript": "^6.0.3",
|
|
24
|
+
"vitest": "^4.1.10"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=22.19.0"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/zhinjs/zhin.git",
|
|
32
|
+
"directory": "packages/im/ai-provider"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc",
|
|
40
|
+
"clean": "rimraf lib",
|
|
41
|
+
"test": "vitest run --root ../../.. packages/im/ai-provider/tests"
|
|
42
|
+
}
|
|
6
43
|
}
|