@dan-ai-studio/dshopencodego 0.1.54 → 0.1.56
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/README.en.md +14 -1
- package/README.md +14 -1
- package/lib/client.js +239 -10
- package/lib/index.js +31441 -174
- package/lib/types/adapter.d.ts +8 -0
- package/lib/types/catalog/gateway.d.ts +6 -1
- package/lib/types/catalog/go-doc-discovery.d.ts +28 -0
- package/lib/types/catalog/index.d.ts +8 -0
- package/lib/types/config.d.ts +6 -0
- package/lib/types/network/contract.d.ts +32 -0
- package/lib/types/network/pinning.d.ts +97 -0
- package/lib/types/network/service.d.ts +27 -0
- package/lib/types/usage/service.d.ts +8 -0
- package/lib/types/usage/windows.d.ts +8 -0
- package/package.json +1 -1
package/lib/types/adapter.d.ts
CHANGED
|
@@ -59,6 +59,14 @@ export interface OpencodeGoAdapterOptions {
|
|
|
59
59
|
* discovery per start and nothing else.
|
|
60
60
|
*/
|
|
61
61
|
readonly cacheDir?: string;
|
|
62
|
+
/**
|
|
63
|
+
* The fetch every gateway request is made through.
|
|
64
|
+
*
|
|
65
|
+
* A factory rather than a function: the pin follows the configuration, and
|
|
66
|
+
* the configuration is live. A request made after a pin was set goes to
|
|
67
|
+
* the pinned address without the adapter being rebuilt.
|
|
68
|
+
*/
|
|
69
|
+
readonly fetch?: () => typeof fetch;
|
|
62
70
|
/**
|
|
63
71
|
* Observe the provider's own usage for one completed call. This is the only
|
|
64
72
|
* honest source of token counts: the gateway's `/usage` endpoint reports
|
|
@@ -11,10 +11,15 @@
|
|
|
11
11
|
export declare function readModelIds(body: unknown): readonly string[];
|
|
12
12
|
/**
|
|
13
13
|
* Fetch the ids the gateway currently advertises.
|
|
14
|
+
*
|
|
15
|
+
* The request goes through the given fetch, so a gateway pinned to one
|
|
16
|
+
* address is read from that address — and, when that address is gone, from
|
|
17
|
+
* the address the system would have chosen.
|
|
14
18
|
* @param baseURL - normalized gateway base without a trailing slash.
|
|
15
19
|
* @param signal - caller cancellation, if any.
|
|
20
|
+
* @param request - the fetch to use; the system's own when none is given.
|
|
16
21
|
* @returns the advertised ids in endpoint order, deduplicated.
|
|
17
22
|
* @throws {LlmError} `DISCOVERY_FAILED` when the endpoint is unreachable, not
|
|
18
23
|
* OK, or does not answer a model listing.
|
|
19
24
|
*/
|
|
20
|
-
export declare function fetchModelIds(baseURL: string, signal?: AbortSignal): Promise<readonly string[]>;
|
|
25
|
+
export declare function fetchModelIds(baseURL: string, signal?: AbortSignal, request?: typeof fetch): Promise<readonly string[]>;
|
|
@@ -24,6 +24,16 @@
|
|
|
24
24
|
*/
|
|
25
25
|
/** A repository listing is large; the cap keeps a hostile response bounded. */
|
|
26
26
|
export declare const DISCOVERY_MAX_BYTES: number;
|
|
27
|
+
/**
|
|
28
|
+
* How long the repository listing waits before it is asked again.
|
|
29
|
+
*
|
|
30
|
+
* The listing is unauthenticated, and an unauthenticated GitHub API allows
|
|
31
|
+
* sixty requests an hour. The listing is also large — the provider's whole
|
|
32
|
+
* tree, thousands of entries. Asking it on every build would spend that
|
|
33
|
+
* budget on a provider that is merely unreachable, and would make every
|
|
34
|
+
* build slower for a question with the same answer.
|
|
35
|
+
*/
|
|
36
|
+
export declare const DISCOVERY_COOLDOWN_MS: number;
|
|
27
37
|
/**
|
|
28
38
|
* The repository paths a discovery run found.
|
|
29
39
|
*
|
|
@@ -76,3 +86,21 @@ export declare function readCachedPaths(cacheDir: string | undefined): readonly
|
|
|
76
86
|
* @returns the merged set, in the order it should be tried.
|
|
77
87
|
*/
|
|
78
88
|
export declare function rememberPaths(cacheDir: string | undefined, discovered: readonly string[]): readonly string[];
|
|
89
|
+
/**
|
|
90
|
+
* Whether the repository may be asked again.
|
|
91
|
+
*
|
|
92
|
+
* The question is worth at most an hour: a provider whose document has
|
|
93
|
+
* moved is found within the hour, and one that is merely down is not asked
|
|
94
|
+
* again every minute while it is down.
|
|
95
|
+
* @param cacheDir - the plugin's cache directory.
|
|
96
|
+
* @returns true when the repository may be asked.
|
|
97
|
+
*/
|
|
98
|
+
export declare function discoveryAllowed(cacheDir: string | undefined): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Record that the repository was asked, whether or not it answered.
|
|
101
|
+
*
|
|
102
|
+
* The attempt is what the budget is spent on, so a question that came back
|
|
103
|
+
* empty counts as a question.
|
|
104
|
+
* @param cacheDir - the plugin's cache directory.
|
|
105
|
+
*/
|
|
106
|
+
export declare function rememberAttempt(cacheDir: string | undefined): void;
|
|
@@ -132,6 +132,14 @@ export interface CatalogOptions {
|
|
|
132
132
|
* nothing else.
|
|
133
133
|
*/
|
|
134
134
|
readonly cacheDir?: string;
|
|
135
|
+
/**
|
|
136
|
+
* The fetch the gateway listing is read through.
|
|
137
|
+
*
|
|
138
|
+
* A factory rather than a function: the pin follows the configuration, and
|
|
139
|
+
* the configuration is live. A catalogue built before a pin was set must
|
|
140
|
+
* read the next listing from the pinned address without being rebuilt.
|
|
141
|
+
*/
|
|
142
|
+
readonly fetch?: () => typeof fetch;
|
|
135
143
|
}
|
|
136
144
|
/**
|
|
137
145
|
* One gateway's catalog. Requests reuse a cached snapshot; explicit discovery
|
package/lib/types/config.d.ts
CHANGED
|
@@ -63,6 +63,12 @@ export interface OpencodeGoConfig {
|
|
|
63
63
|
* The escape hatch for a model whose family rule guessed wrong.
|
|
64
64
|
*/
|
|
65
65
|
modelProtocols: Record<string, string>;
|
|
66
|
+
/**
|
|
67
|
+
* Addresses a name should be sent to instead of the one the system
|
|
68
|
+
* resolves, by host name. A name that is not listed keeps the system's
|
|
69
|
+
* own resolution, and so keeps its own fallback.
|
|
70
|
+
*/
|
|
71
|
+
pinnedAddresses: Record<string, string>;
|
|
66
72
|
/**
|
|
67
73
|
* Retry policy for this route, owned here and executed by the optional
|
|
68
74
|
* `dsh-llm-retry` plugin. Absent leaves the host's own default in force.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire contract for the network Remote.
|
|
3
|
+
*
|
|
4
|
+
* One reading, answering one question: which address is the gateway sent to
|
|
5
|
+
* right now, and did that address survive its first request?
|
|
6
|
+
*
|
|
7
|
+
* A spent address is not a failure the user has to fix — the requests are
|
|
8
|
+
* being served by the system's own resolution, and this says so.
|
|
9
|
+
*
|
|
10
|
+
* @module @dan-ai-studio/dshopencodego/network/contract
|
|
11
|
+
*/
|
|
12
|
+
import type { RemoteResult, TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol';
|
|
13
|
+
/** The gateway's name and the address it is pinned to. */
|
|
14
|
+
export interface NetworkReading {
|
|
15
|
+
/** The gateway's name. */
|
|
16
|
+
readonly host: string;
|
|
17
|
+
/** The address the name is pinned to; absent when nothing is pinned. */
|
|
18
|
+
readonly address?: string;
|
|
19
|
+
/** Whether the pinned address was found to be gone. */
|
|
20
|
+
readonly failed?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Validate a network reading crossing the wire. */
|
|
23
|
+
export declare function parseNetworkReading(value: unknown): NetworkReading;
|
|
24
|
+
declare module '@deepseek-ai/dsh-typert-protocol' {
|
|
25
|
+
interface TypertRemoteNamespaceMap {
|
|
26
|
+
opencodeGoNetwork: {
|
|
27
|
+
readNetwork(): Promise<RemoteResult<NetworkReading>>;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Remote methods this package owns, mounted together by the plugin. */
|
|
32
|
+
export declare const networkRemote: TypertRemoteContribution;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pinning a name to an address.
|
|
3
|
+
*
|
|
4
|
+
* A name that the system resolves may reach an edge that is far away, and
|
|
5
|
+
* a far edge costs every request. Pinning the name to another address of the
|
|
6
|
+
* same network sends it to a different edge instead.
|
|
7
|
+
*
|
|
8
|
+
* The certificate is still checked against the name: only the resolution
|
|
9
|
+
* changes, never the name the server is asked to prove. That is why this
|
|
10
|
+
* is a lookup and not a redirect.
|
|
11
|
+
*
|
|
12
|
+
* Only the gateway's own name is pinned. Every other name — the metadata
|
|
13
|
+
* registry, the provider's documentation — keeps the system's own
|
|
14
|
+
* resolution, including its fallback, its cache, and whatever the host's
|
|
15
|
+
* resolver decides.
|
|
16
|
+
*
|
|
17
|
+
* A pin that cannot be reached is not the end of the request. The address may
|
|
18
|
+
* be gone, and the name may still be served perfectly well by the address the
|
|
19
|
+
* system would have chosen — so the request is sent again, that way, and the
|
|
20
|
+
* answer is the one the caller gets. A wrong address must never cost more
|
|
21
|
+
* than no address at all, so the pin is remembered as spent and the rest of
|
|
22
|
+
* the requests go straight to the system's resolution.
|
|
23
|
+
*
|
|
24
|
+
* @module @dan-ai-studio/dshopencodego/network/pinning
|
|
25
|
+
*/
|
|
26
|
+
/** A name and the address it should be sent to. */
|
|
27
|
+
export type PinnedAddresses = Readonly<Record<string, string>>;
|
|
28
|
+
/**
|
|
29
|
+
* The gateway's own name and the address it is pinned to.
|
|
30
|
+
*
|
|
31
|
+
* An absent address is the whole point of the type: nothing is pinned, and
|
|
32
|
+
* every request goes to the system's own resolution, untouched.
|
|
33
|
+
*/
|
|
34
|
+
export interface GatewayPin {
|
|
35
|
+
/** The gateway's name, lowercased. */
|
|
36
|
+
readonly host: string;
|
|
37
|
+
/** The address the name is sent to; absent when nothing is pinned. */
|
|
38
|
+
readonly address?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The gateway's own name, as the configured endpoint states it.
|
|
42
|
+
*
|
|
43
|
+
* The endpoint is where every request of this plugin goes, so its name is
|
|
44
|
+
* the only one worth pinning: a name nobody here asks for has no request to
|
|
45
|
+
* redirect.
|
|
46
|
+
* @param baseURL - the configured gateway base.
|
|
47
|
+
* @returns the lowercased host, or an empty string when the endpoint is not
|
|
48
|
+
* a URL this plugin can parse.
|
|
49
|
+
*/
|
|
50
|
+
export declare function gatewayHostOf(baseURL: string): string;
|
|
51
|
+
/**
|
|
52
|
+
* The pin that applies to the configured gateway.
|
|
53
|
+
*
|
|
54
|
+
* A pin for another name is not this plugin's business: the endpoint is what
|
|
55
|
+
* this plugin asks for, and a name that is not the endpoint's is never on
|
|
56
|
+
* the path of a request. An address that is not an address is a typo worth
|
|
57
|
+
* ignoring rather than a crash in the middle of a request, and ignoring it
|
|
58
|
+
* means the request goes to the system's resolution — which is exactly what
|
|
59
|
+
* an unconfigured plugin does.
|
|
60
|
+
* @param pins - the configured pins.
|
|
61
|
+
* @param baseURL - the configured gateway base.
|
|
62
|
+
* @returns the gateway's name and, when one is configured and usable, the
|
|
63
|
+
* address it is pinned to.
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveGatewayPin(pins: PinnedAddresses, baseURL: string): GatewayPin;
|
|
66
|
+
/**
|
|
67
|
+
* Close the dispatcher, if one is open.
|
|
68
|
+
*
|
|
69
|
+
* The plugin's own lifetime is the host's, so this is only for a test or
|
|
70
|
+
* a shutdown that wants the sockets gone now.
|
|
71
|
+
*/
|
|
72
|
+
export declare function closeDispatcher(): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Whether the pinned address was already found to be gone.
|
|
75
|
+
*
|
|
76
|
+
* A spent address is not tried again: the request that proved it gone is
|
|
77
|
+
* the one that paid for it, and every later request would pay the same price
|
|
78
|
+
* for the same answer.
|
|
79
|
+
* @param pin - the pin.
|
|
80
|
+
* @returns true when the address was found to be gone.
|
|
81
|
+
*/
|
|
82
|
+
export declare function isPinSpent(pin: GatewayPin): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* A fetch that sends the gateway's name to the pinned address.
|
|
85
|
+
*
|
|
86
|
+
* A request for another name is sent exactly as it would have been: the
|
|
87
|
+
* dispatcher only answers the name it was given, and the rest keep the
|
|
88
|
+
* system's own resolution.
|
|
89
|
+
*
|
|
90
|
+
* A pinned address that cannot be reached is not the end of the request.
|
|
91
|
+
* The address may be gone, and the name may still be served perfectly well
|
|
92
|
+
* by the address the system would have chosen — so the request is sent
|
|
93
|
+
* again, that way, and the answer is the one the caller gets.
|
|
94
|
+
* @param pin - the gateway's name and its pinned address.
|
|
95
|
+
* @returns the fetch to use.
|
|
96
|
+
*/
|
|
97
|
+
export declare function gatewayFetch(pin: GatewayPin): typeof fetch;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host half of the network Remote.
|
|
3
|
+
*
|
|
4
|
+
* The page needs to know which address the gateway is sent to, and whether
|
|
5
|
+
* that address is still working: a pin that was found to be gone leaves the
|
|
6
|
+
* requests on the system's own resolution, and a page that kept showing the
|
|
7
|
+
* old address would claim a speed the plugin is no longer delivering.
|
|
8
|
+
*
|
|
9
|
+
* @module @dan-ai-studio/dshopencodego/network/service
|
|
10
|
+
*/
|
|
11
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
12
|
+
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
13
|
+
import type { NetworkReading } from './contract.ts';
|
|
14
|
+
/** Host inputs for the network service. */
|
|
15
|
+
export interface NetworkServiceOptions {
|
|
16
|
+
/** Current gateway base URL. */
|
|
17
|
+
readonly baseURL: () => string;
|
|
18
|
+
/** The configured pins, by host name. */
|
|
19
|
+
readonly pinnedAddresses: () => Readonly<Record<string, string>>;
|
|
20
|
+
}
|
|
21
|
+
/** The network Remote: the gateway's name, its pin, and that pin's health. */
|
|
22
|
+
export declare class OpencodeGoNetworkService extends TypertRemoteService {
|
|
23
|
+
private readonly options;
|
|
24
|
+
constructor(ctx: Context, options: NetworkServiceOptions);
|
|
25
|
+
/** The gateway's name and its pin, as the configuration states them. */
|
|
26
|
+
readNetwork(): Promise<NetworkReading>;
|
|
27
|
+
}
|
|
@@ -22,6 +22,14 @@ export interface UsageServiceOptions {
|
|
|
22
22
|
readonly resolveApiKey: () => Promise<string | undefined>;
|
|
23
23
|
/** The process-lifetime meter fed by the adapter. */
|
|
24
24
|
readonly meter: UsageMeter;
|
|
25
|
+
/**
|
|
26
|
+
* The fetch the usage read is made through.
|
|
27
|
+
*
|
|
28
|
+
* A factory rather than a function: the pin follows the configuration, and
|
|
29
|
+
* the configuration is live. A read made after a pin was set goes to the
|
|
30
|
+
* pinned address without the service being rebuilt.
|
|
31
|
+
*/
|
|
32
|
+
readonly fetch?: () => typeof fetch;
|
|
25
33
|
}
|
|
26
34
|
/**
|
|
27
35
|
* Decide what one failed read means for the client.
|
|
@@ -40,6 +40,14 @@ interface UsageReadOptions {
|
|
|
40
40
|
/** Opaque identity of the endpoint and credential pair, when known. */
|
|
41
41
|
readonly source?: string;
|
|
42
42
|
readonly signal?: AbortSignal;
|
|
43
|
+
/**
|
|
44
|
+
* The fetch to use.
|
|
45
|
+
*
|
|
46
|
+
* The read goes to the gateway, so a gateway pinned to one address is read
|
|
47
|
+
* from that address — and, when that address is gone, from the address the
|
|
48
|
+
* system would have chosen.
|
|
49
|
+
*/
|
|
50
|
+
readonly request?: typeof fetch;
|
|
43
51
|
}
|
|
44
52
|
/**
|
|
45
53
|
* Read the account's usage windows.
|
package/package.json
CHANGED