dsh-opencode-go 0.1.24 → 0.2.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.
Files changed (102) hide show
  1. package/README.en.md +66 -12
  2. package/README.md +172 -79
  3. package/THIRD_PARTY_NOTICES.md +6 -2
  4. package/assets/icon.png +0 -0
  5. package/docs/advanced.en.md +32 -35
  6. package/docs/advanced.md +33 -35
  7. package/docs/assets/logo-dark.png +0 -0
  8. package/docs/assets/logo-light.png +0 -0
  9. package/docs/assets/usage-history-desktop.jpg +0 -0
  10. package/docs/assets/usage-history-mobile.jpg +0 -0
  11. package/docs/assets/usage-history-models.jpg +0 -0
  12. package/docs/development.md +61 -119
  13. package/docs/independent-package.md +4 -2
  14. package/docs/usage-analytics.en.md +57 -0
  15. package/docs/usage-analytics.md +57 -0
  16. package/docs/verification.md +51 -917
  17. package/lib/build-info.json +1 -1
  18. package/lib/client.js +3429 -2618
  19. package/lib/free-http-worker.js +32 -0
  20. package/lib/index.js +5135 -3746
  21. package/lib/types/accounts.d.ts +96 -31
  22. package/lib/types/adapter.d.ts +63 -51
  23. package/lib/types/analytics.d.ts +35 -0
  24. package/lib/types/catalog.d.ts +109 -44
  25. package/lib/types/client/AnalyticsDialog.d.ts +18 -0
  26. package/lib/types/client/Section.d.ts +41 -7
  27. package/lib/types/client/UsagePill.d.ts +15 -6
  28. package/lib/types/client/controller.d.ts +178 -0
  29. package/lib/types/client/dashboard-copy.d.ts +58 -0
  30. package/lib/types/client/index.d.ts +18 -12
  31. package/lib/types/client/{locales.d.ts → presentation.d.ts} +97 -9
  32. package/lib/types/config.d.ts +14 -15
  33. package/lib/types/contracts.d.ts +338 -0
  34. package/lib/types/conversion.d.ts +155 -0
  35. package/lib/types/free-channel.d.ts +21 -0
  36. package/lib/types/free-http-worker.d.ts +1 -0
  37. package/lib/types/free-policy.d.ts +4 -0
  38. package/lib/types/free-protocol.d.ts +16 -0
  39. package/lib/types/free-runtime.d.ts +2 -0
  40. package/lib/types/free-socks-tunnel.d.ts +4 -0
  41. package/lib/types/free-transport.d.ts +19 -0
  42. package/lib/types/index.d.ts +8 -40
  43. package/lib/types/pricing.d.ts +29 -0
  44. package/lib/types/sdk-types.d.ts +1540 -2902
  45. package/lib/types/transport.d.ts +71 -0
  46. package/lib/vendor-licenses.txt +55 -31
  47. package/package.json +77 -78
  48. package/docs/assets/usage-panel.png +0 -0
  49. package/docs/fork-review-2026-09-25.md +0 -191
  50. package/docs/native-call-comparison-v020-rc2.md +0 -116
  51. package/lib/types/account-manager.d.ts +0 -25
  52. package/lib/types/account-operations.d.ts +0 -31
  53. package/lib/types/account-policy.d.ts +0 -16
  54. package/lib/types/account-recovery.d.ts +0 -2
  55. package/lib/types/account-selection.d.ts +0 -30
  56. package/lib/types/account-service.d.ts +0 -12
  57. package/lib/types/accounts-contract.d.ts +0 -38
  58. package/lib/types/call-trace.d.ts +0 -54
  59. package/lib/types/catalog-manager.d.ts +0 -20
  60. package/lib/types/client/AccountsCard.d.ts +0 -19
  61. package/lib/types/client/ModelEditor.d.ts +0 -20
  62. package/lib/types/client/accounts-controller.d.ts +0 -71
  63. package/lib/types/client/hint-mark.d.ts +0 -17
  64. package/lib/types/client/host-compat.d.ts +0 -7
  65. package/lib/types/client/host-primitives.d.ts +0 -11
  66. package/lib/types/client/section-controller.d.ts +0 -202
  67. package/lib/types/client/settings.d.ts +0 -18
  68. package/lib/types/client/staged-form.d.ts +0 -201
  69. package/lib/types/client/usage.d.ts +0 -4
  70. package/lib/types/config-contract.d.ts +0 -70
  71. package/lib/types/conversion/config.d.ts +0 -4
  72. package/lib/types/conversion/context.d.ts +0 -56
  73. package/lib/types/conversion/image-offload.d.ts +0 -13
  74. package/lib/types/conversion/image-pool.d.ts +0 -24
  75. package/lib/types/conversion/index.d.ts +0 -5
  76. package/lib/types/conversion/replay.d.ts +0 -66
  77. package/lib/types/conversion/stream.d.ts +0 -44
  78. package/lib/types/gateway-diagnostics.d.ts +0 -23
  79. package/lib/types/gateway-error.d.ts +0 -2
  80. package/lib/types/gateway-url.d.ts +0 -6
  81. package/lib/types/google-fetch.d.ts +0 -6
  82. package/lib/types/host-settings.d.ts +0 -11
  83. package/lib/types/json-response.d.ts +0 -14
  84. package/lib/types/metadata-cache.d.ts +0 -12
  85. package/lib/types/model-metadata.d.ts +0 -21
  86. package/lib/types/models-contract.d.ts +0 -66
  87. package/lib/types/models.d.ts +0 -13
  88. package/lib/types/protocol-contract.d.ts +0 -5
  89. package/lib/types/protocol-policy.d.ts +0 -4
  90. package/lib/types/provider-identity.d.ts +0 -4
  91. package/lib/types/proxy-url.d.ts +0 -2
  92. package/lib/types/proxy.d.ts +0 -11
  93. package/lib/types/reasoning.d.ts +0 -40
  94. package/lib/types/remote-contract.d.ts +0 -3
  95. package/lib/types/remotes.d.ts +0 -3
  96. package/lib/types/request-budget.d.ts +0 -12
  97. package/lib/types/request-control.d.ts +0 -2
  98. package/lib/types/settings-bridge.d.ts +0 -22
  99. package/lib/types/usage-contract.d.ts +0 -35
  100. package/lib/types/usage-display.d.ts +0 -4
  101. package/lib/types/usage.d.ts +0 -27
  102. /package/lib/types/{google-generative-ai.d.ts → google.d.ts} +0 -0
@@ -1,33 +1,98 @@
1
- /** Client-safe account metadata. Secrets stay in the host credential service. */
2
- import type { GoAccountOperation } from './account-operations.ts';
3
- export type GoAccount = {
4
- id: string;
5
- name: string;
6
- apiKeyEnv: string;
7
- };
8
- export declare const MAX_ACCOUNTS = 20;
9
- export declare const ACCOUNT_REF_PREFIX = "DSH_OPENCODE_GO_ACCOUNT_";
10
- export declare const DEFAULT_ACCOUNT_REF = "OPENCODE_API_KEY";
11
- /** A credential reference is a bare environment variable name, never empty or decorated. */
12
- export declare const ACCOUNT_REF_PATTERN: RegExp;
13
- export interface AccountSettings {
14
- apiKeyEnv?: string;
15
- /** Omission/null preserves legacy credentials; an explicit empty list removes all accounts. */
16
- accounts?: readonly GoAccount[] | null;
17
- autoSwitch?: boolean;
18
- /** Recovery intentions owned by this exact settings/profile document. */
19
- accountOperations?: readonly GoAccountOperation[];
1
+ /** Serialized account commands, primary selection and official quota reads. */
2
+ import { type SettingsWriteResult, type GoAccountSwitch, type AccountCommand, type GoUsage } from './contracts.ts';
3
+ import { type CredentialProvider } from '@deepseek-ai/dsh-credentials';
4
+ import type { GoAccountSettlement } from './adapter.ts';
5
+ import { type OpencodeGoConfig } from './config.ts';
6
+ import type { Context } from '@deepseek-ai/cordis';
7
+ import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
8
+ import { ProxyTransport } from './transport.ts';
9
+ export interface AccountSettingsWriter {
10
+ describe(): readonly {
11
+ ns: string;
12
+ revision: number;
13
+ value: unknown;
14
+ }[];
15
+ mutate(ns: string, ops: readonly {
16
+ op: 'set';
17
+ path: string[];
18
+ value: unknown;
19
+ }[], expectedRevision?: number): Promise<unknown>;
20
20
  }
21
- export declare function accountRefOf(settings: AccountSettings): string;
22
- /** Promote one account while preserving every other account's relative order. */
23
- export declare function moveAccountFirst(accounts: readonly GoAccount[], ref: string): readonly GoAccount[];
24
- /** Read legacy selections as the first account until the host persists their order. */
25
- export declare function accountsOf(settings: AccountSettings): readonly GoAccount[];
26
- export declare function assertAccounts(accounts: readonly GoAccount[] | null | undefined, selectedRef?: string): void;
27
- /** Safe UI notice for a successful request using a fallback account. */
28
- export interface GoAccountSwitch {
29
- fromRef: string;
30
- toRef: string;
31
- reason: 'quota' | 'credential';
32
- at: number;
21
+ /** Locate the profile entry that owns this mount's account metadata. */
22
+ export declare function accountSettingsRow(settings: AccountSettingsWriter): {
23
+ ns: string;
24
+ revision: number;
25
+ value: unknown;
26
+ } | undefined;
27
+ export interface AttemptOutcome {
28
+ failure?: {
29
+ code: string;
30
+ };
31
+ emitted: boolean;
32
+ totalTokens: number;
33
+ aborted: boolean;
34
+ hasNext: boolean;
33
35
  }
36
+ /** Switching accounts must never replay output, charged work or model permission failures. */
37
+ export declare function accountFallback(outcome: AttemptOutcome): GoAccountSwitch['reason'] | undefined;
38
+ /** Only credential, rate and quota failures cool down a key; PERMISSION_DENIED is model-scoped. */
39
+ export declare function isGatewayKeyRejection(failure: {
40
+ code: string;
41
+ }): boolean;
42
+ type AccountCredentials = Pick<CredentialProvider, 'describe' | 'resolve' | 'set' | 'unset'>;
43
+ /** One mount serializes account edits, credential writes and fallback promotion in memory. */
44
+ export declare class GoAccountManager {
45
+ private readonly config;
46
+ private readonly logger;
47
+ private connection;
48
+ private queue;
49
+ private generation;
50
+ private signature;
51
+ private credentialGeneration;
52
+ private latestSeq;
53
+ private notice;
54
+ constructor(config: () => OpencodeGoConfig, logger: {
55
+ warn(message: string): void;
56
+ });
57
+ connect(settings: AccountSettingsWriter, credentials: AccountCredentials): () => void;
58
+ private enqueue;
59
+ private read;
60
+ private write;
61
+ execute(raw: AccountCommand): Promise<SettingsWriteResult>;
62
+ private executeCommand;
63
+ /** A freshness fence prevents an old request from overriding a later user choice. */
64
+ capture(): number;
65
+ credentialChanged(): void;
66
+ lastSwitch(): GoAccountSwitch | undefined;
67
+ settle(event: GoAccountSettlement): void;
68
+ }
69
+ /** The browser sends commands; the host owns credentials and metadata writes. */
70
+ export declare class GoAccountsService extends TypertRemoteService {
71
+ private readonly options;
72
+ constructor(ctx: Context, options: {
73
+ manager: GoAccountManager;
74
+ });
75
+ execute(command: AccountCommand): Promise<SettingsWriteResult>;
76
+ }
77
+ interface UsageOptions {
78
+ baseURL: () => string;
79
+ proxyURL?: () => string;
80
+ transport?: ProxyTransport;
81
+ resolveApiKey: (ref?: string) => Promise<string | undefined>;
82
+ activeRef?: () => string;
83
+ accountRefs?: () => readonly string[];
84
+ lastSwitch?: () => GoAccountSwitch | undefined;
85
+ }
86
+ /** Account statistics are fetched on the Host; credentials never enter the browser. */
87
+ export declare class GoUsageService extends TypertRemoteService {
88
+ private readonly options;
89
+ private readonly identities;
90
+ private readonly pending;
91
+ private readonly transport;
92
+ constructor(ctx: Context, options: UsageOptions);
93
+ read(): Promise<GoUsage>;
94
+ readAccount(ref: string): Promise<GoUsage>;
95
+ private readRef;
96
+ private fetchUsage;
97
+ }
98
+ export {};
@@ -1,35 +1,22 @@
1
- /**
2
- * The OpenCode Go adapter: one route, one catalog, per-request routing header.
3
- *
4
- * Every request to the gateway carries two Harness-owned headers: the
5
- * attribution User-Agent (`deepseek-harness/<version>`), which pi-ai's client
6
- * lets request headers override, and `x-opencode-session`, which the gateway
7
- * requires and uses to route a conversation and share its prompt cache. The
8
- * header value is the request's session id, stable across continuation and
9
- * restore. Actual cache reads remain an upstream usage fact. A request with no
10
- * session id gets a fresh random value rather than a shared constant, because
11
- * a constant would merge unrelated traffic into one cache bucket.
12
- *
13
- * Multi-turn correctness rides on the shared pi-ai conversion machinery
14
- * (`toPiContext` reconstructs provider-native replay state from the session
15
- * log; `toStreamChunks` maps events to seam chunks), so assistant history,
16
- * tool calls, and usage land in the session log exactly as the generic pi-ai
17
- * adapter records them. Image content rides the same machinery: models whose
18
- * catalog entry declares the image modality convert attachments through the
19
- * durable attachment service, and every other model refuses image content
20
- * before any provider I/O.
21
- *
22
- * @module dsh-llm-opencode-go/adapter
23
- */
24
- import { LlmAdapter } from '@deepseek-ai/dsh-llm';
25
- import type { GenerateOptions, ImageAttachmentAccess, LlmModelInfo, LlmResolvedModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm';
1
+ /** Request snapshots, SDK dispatch, deadlines and seamless account fallback. */
2
+ import { type OpencodeGoModelLimits, type GoAccountSwitch, type ModelSource } from './contracts.ts';
3
+ import { type GenerateOptions, type ImageAttachmentAccess, type StreamChunk, LlmAdapter, type LlmModelInfo, type LlmResolvedModelInfo } from '@deepseek-ai/dsh-llm';
26
4
  import type { AttachmentStore, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
5
+ import type { Api, Model, Provider } from './sdk-types.ts';
6
+ import { type OpencodeGoConfig } from './config.ts';
7
+ import { ProxyTransport } from './transport.ts';
27
8
  import { OpencodeGoCatalog } from './catalog.ts';
28
- import { ProxyTransport } from './proxy.ts';
29
- import type { OpencodeGoConfig } from './config.ts';
30
- import { type GoAccountSwitch } from './accounts.ts';
31
- import { type GoCallTrace } from './call-trace.ts';
32
- export type { GoCallTrace } from './call-trace.ts';
9
+ import { FreeBunTransport } from './free-transport.ts';
10
+ import { FreeChannelState } from './free-channel.ts';
11
+ /**
12
+ * Cap large models at 64k unless the caller or settings specify an allowance.
13
+ * Per-model settings continue to cap explicit caller values.
14
+ */
15
+ export declare function requestMaxTokens(model: {
16
+ id: string;
17
+ maxTokens: number;
18
+ source?: ModelSource;
19
+ }, limits: OpencodeGoModelLimits, requested?: number): number | undefined;
33
20
  /**
34
21
  * The attachment-service bridges one image request reads. Construction-time
35
22
  * (context-dependent); the config-dependent policy numbers are merged per
@@ -41,6 +28,38 @@ export interface OpencodeGoImageAccess {
41
28
  /** Bridge one attachment reference into the current model-tool execution world. */
42
29
  resolveImageAccess: (attachments: AttachmentStore, ref: ImageAttachmentRef) => ImageAttachmentAccess | undefined;
43
30
  }
31
+ /** Host dependencies used by a single attempt, independent of account selection. */
32
+ export interface OpencodeGoRequestExecutorOptions {
33
+ /** Free-only passive backoff; never consulted by the Go executor. */
34
+ freeChannel?: FreeChannelState;
35
+ /** Resolve the credential reference captured with this call's endpoint; missing must fail loud. */
36
+ resolveApiKey: (config: OpencodeGoConfig, signal?: AbortSignal) => Promise<string | undefined>;
37
+ /**
38
+ * Image input machinery; absent refuses image content, which is the posture
39
+ * for direct construction without a durable attachment service behind it.
40
+ */
41
+ imageAccess?: OpencodeGoImageAccess;
42
+ /** Observe assistant history degrading to provider-neutral conversion. */
43
+ onReplayDegrade?: (reason: string) => void;
44
+ }
45
+ /** Inputs already resolved by the adapter, including one account and the wire session ID. */
46
+ export interface OpencodeGoRequestSnapshot {
47
+ config: OpencodeGoConfig;
48
+ model: Model<Api>;
49
+ provider: Provider;
50
+ sessionId: string;
51
+ apiKey?: string;
52
+ }
53
+ /** Shares the adapter's transport without owning its lifetime or retrying accounts. */
54
+ export declare class OpencodeGoRequestExecutor {
55
+ private readonly options;
56
+ private readonly transport;
57
+ private readonly freeTransport;
58
+ constructor(options: OpencodeGoRequestExecutorOptions, transport: ProxyTransport, freeTransport?: FreeBunTransport);
59
+ /** One account, one SDK attempt; host recovery still owns failures after output. */
60
+ stream(options: GenerateOptions, snapshot: OpencodeGoRequestSnapshot): AsyncIterable<StreamChunk>;
61
+ private attempt;
62
+ }
44
63
  /** One request's serving account, with the identity captured before discovery. */
45
64
  export interface GoAccountSettlement {
46
65
  seq: number;
@@ -50,63 +69,58 @@ export interface GoAccountSettlement {
50
69
  notice?: GoAccountSwitch;
51
70
  }
52
71
  /** Constructor inputs for {@link OpencodeGoAdapter}. */
53
- export interface OpencodeGoAdapterOptions {
72
+ export interface OpencodeGoAdapterOptions extends OpencodeGoRequestExecutorOptions {
73
+ source?: ModelSource;
54
74
  /** Shared with Host usage reads for this plugin mount. */
55
75
  transport?: ProxyTransport;
56
76
  /** Mount-owned discovery; direct construction supplies its own manager. */
57
77
  catalog?: (config: OpencodeGoConfig) => OpencodeGoCatalog;
58
- /** Optional directory for bounded HTTP error evidence; request contents are omitted. */
59
- debugDirectory?: () => string | undefined;
60
78
  /**
61
79
  * The current configuration, re-read at every operation: a settings write
62
80
  * reaches the next request without a restart, and one operation never mixes
63
81
  * two configuration generations.
64
82
  */
65
83
  config: () => OpencodeGoConfig;
66
- /** Resolve the credential reference captured with this call's endpoint; missing must fail loud. */
67
- resolveApiKey: (config: OpencodeGoConfig, signal?: AbortSignal) => Promise<string | undefined>;
68
- /** Observe one bounded, content-free summary for every dispatched call. */
69
- onCallTrace?: (trace: GoCallTrace) => void;
70
- /**
71
- * Image input machinery; absent refuses image content, which is the posture
72
- * for direct construction without a durable attachment service behind it.
73
- */
74
- imageAccess?: OpencodeGoImageAccess;
75
- /** Observe the catalog falling back to the curated table. */
84
+ /** Observe discovery retaining its last successful directory. */
76
85
  onFallback?: (detail: {
77
86
  url: string;
78
87
  error: unknown;
79
88
  kept: number;
80
89
  }) => void;
81
- /** Observe live ids the curated table cannot route. */
90
+ /** Observe chat rows with invalid or unsupported declarations. */
82
91
  onOmitted?: (ids: readonly string[]) => void;
83
92
  onCatalogWarning?: (warning: string) => void;
84
- /** Observe assistant history degrading to provider-neutral conversion. */
85
- onReplayDegrade?: (reason: string) => void;
86
93
  /** Re-read picker models after a background catalog refresh commits. */
87
94
  onCatalogRefresh?: () => void;
88
95
  /** Host account-state version for actual requests, captured before asynchronous model discovery. */
89
96
  accountGeneration?: () => number;
97
+ /** Shared by both adapters so account settlement ordering spans both routes. */
98
+ nextCallSequence?: () => number;
90
99
  /** One outcome for both the displayed notice and the persisted selection. */
91
100
  onAccountSettled?: (event: GoAccountSettlement) => void;
92
101
  /** Legacy notice observer. Hosts that persist selection should use onAccountSettled. */
93
102
  onAccountSwitch?: (notice: GoAccountSwitch | undefined, config: OpencodeGoConfig, seq: number) => void;
94
103
  }
95
104
  /**
96
- * The single route's adapter. The catalog snapshot freezes at each operation,
105
+ * One source's route adapter. The catalog snapshot freezes at each operation,
97
106
  * so a refresh between two requests never mixes model generations inside one
98
107
  * call.
99
108
  */
100
109
  export declare class OpencodeGoAdapter extends LlmAdapter {
101
110
  private readonly options;
111
+ private readonly source;
102
112
  private readonly resolveCatalog;
103
113
  private readonly transport;
114
+ private readonly requestExecutor;
115
+ private readonly freeTransport;
116
+ private readonly freeChannel;
104
117
  /** Per-reference rejection deadlines, isolated by the gateway that rejected it. */
105
118
  private readonly rejectedKeys;
106
119
  /** Reference updates invalidate rejections from attempts using an older key. */
107
120
  private readonly credentialVersions;
108
121
  /** Monotonic sequence of the latest request this adapter started. */
109
122
  private callSeq;
123
+ private nextCallSequence;
110
124
  constructor(options: OpencodeGoAdapterOptions);
111
125
  dispose(): Promise<void>;
112
126
  /**
@@ -132,15 +146,13 @@ export declare class OpencodeGoAdapter extends LlmAdapter {
132
146
  }>;
133
147
  /** Report the same default allowance used by dispatch so the host can budget compaction. */
134
148
  private modelInfo;
135
- /** Validate an explicit effort against the model's own levels, without clamping. */
136
- private resolveReasoningLevel;
137
149
  stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
138
150
  private streamWithSnapshot;
139
151
  private dispatch;
140
152
  private streamAccounts;
153
+ /** Resolve Free keys only when selecting an account or retrying a failed attempt. */
154
+ private accountCandidates;
141
155
  private rememberRejectedKey;
142
156
  /** A stored change to a reference outranks the gateway's last rejection of it. */
143
157
  forgetRejectedKey(ref: string): void;
144
- /** One account, one SDK attempt; host recovery still owns failures after output. */
145
- private streamAttempt;
146
158
  }
@@ -0,0 +1,35 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
3
+ import { type AnalyticsQuery, type AnalyticsReport, type AnalyticsExport } from './contracts.ts';
4
+ import { ProxyTransport } from './transport.ts';
5
+ export declare const ANALYTICS_MAX_BYTES: number;
6
+ export interface AnalyticsOptions {
7
+ baseURL: () => string;
8
+ proxyURL?: () => string;
9
+ transport?: ProxyTransport;
10
+ resolveApiKey: (ref: string) => Promise<string | undefined>;
11
+ accountRefs: () => readonly string[];
12
+ now?: () => number;
13
+ fetch?: typeof globalThis.fetch;
14
+ }
15
+ /** The Host retains the official CSV; ordinary reads expose only aggregate numbers. */
16
+ export declare class GoAnalyticsService extends TypertRemoteService {
17
+ private readonly options;
18
+ private readonly identities;
19
+ private readonly cache;
20
+ private readonly pending;
21
+ private readonly active;
22
+ private readonly transport;
23
+ constructor(ctx: Context, options: AnalyticsOptions);
24
+ read(raw: AnalyticsQuery, signal?: AbortSignal): Promise<AnalyticsReport>;
25
+ exportCsv(raw: AnalyticsQuery, signal?: AbortSignal): Promise<AnalyticsExport>;
26
+ private now;
27
+ private query;
28
+ private failure;
29
+ private forget;
30
+ private network;
31
+ private assertCurrentNetwork;
32
+ private identity;
33
+ private dataset;
34
+ private fetchDataset;
35
+ }
@@ -1,71 +1,136 @@
1
- import type { Api, Model, Provider } from './sdk-types.ts';
2
- import type { LlmDiscoveredModel } from '@deepseek-ai/dsh-llm';
3
- import { type GoModelCatalog } from './models-contract.ts';
4
- import type { ModelMetadata } from './model-metadata.ts';
5
- export { PROVIDER_ID, DISPLAY_NAME } from './provider-identity.ts';
6
- export { DEFAULT_BASE_URL } from './gateway-url.ts';
1
+ import { type LlmDiscoveredModel } from '@deepseek-ai/dsh-llm';
2
+ import type { Api, Model, ModelThinkingLevel, ThinkingBudgets, ThinkingLevelMap, Provider } from './sdk-types.ts';
3
+ import { type ThinkingBudgetRange, type GoModel, type OpencodeGoConfig, type ModelSource, type GoModelCatalog } from './contracts.ts';
4
+ import { type ProxyTransport } from './transport.ts';
5
+ import type { Context } from '@deepseek-ai/cordis';
6
+ import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
7
+ export declare const THINKING_LEVELS: readonly ModelThinkingLevel[];
8
+ /** Protocol formats whose switch/budget is understood by pi-ai. */
9
+ export declare const NATIVE_THINKING_FLAGS: ReadonlySet<string>;
10
+ /** Expose budgets only when the SDK knows where to serialize a numeric limit. */
11
+ export declare function supportsThinkingBudget(api: Api, compat: Model<Api>['compat']): boolean;
12
+ export declare function reasoningBudgetRange(model: Model<Api>): ThinkingBudgetRange | undefined;
13
+ export declare function unsupportedThinkingLevels(): ThinkingLevelMap;
14
+ export declare function reasoningChoices(model: Model<Api>): readonly {
15
+ id: string;
16
+ name: string;
17
+ }[];
18
+ export type ReasoningIntent = {
19
+ kind: 'default';
20
+ } | {
21
+ kind: 'off';
22
+ } | {
23
+ kind: 'on';
24
+ } | {
25
+ kind: 'effort';
26
+ level: Exclude<ModelThinkingLevel, 'off'>;
27
+ } | {
28
+ kind: 'budget';
29
+ tokens: number;
30
+ min: number;
31
+ };
32
+ /** Called after validation against the model's choices. */
33
+ export declare function reasoningIntent(model: Model<Api>, level: string | undefined): ReasoningIntent;
34
+ /**
35
+ * The SDK serializes explicit choices. Default must leave all thinking controls
36
+ * to the service; a switch's On must not acquire an invented effort spelling.
37
+ */
38
+ export declare function reasoningRequest(intent: ReasoningIntent): {
39
+ reasoning?: Exclude<ModelThinkingLevel, 'off'>;
40
+ thinkingBudgets?: ThinkingBudgets;
41
+ onPayload: (payload: unknown) => unknown;
42
+ };
43
+ export type ModelDetails = Pick<GoModel, 'deprecated' | 'releaseDate' | 'inputModalities'> & {
44
+ readonly costKnown?: false;
45
+ };
46
+ export interface ModelDirectory {
47
+ readonly models: ReadonlyMap<string, Model<Api>>;
48
+ readonly details: ReadonlyMap<string, ModelDetails>;
49
+ readonly errors: ReadonlyMap<string, string>;
50
+ readonly warning?: string;
51
+ }
52
+ /** Official listings own their protocol endpoints; custom gateways keep their prefix. */
53
+ export declare function modelBaseURL(api: Api, baseURL: string, declared?: unknown, source?: ModelSource): string;
54
+ export declare function readLiveModelIds(body: unknown, onInvalidRows?: (warning: string) => void): readonly string[];
55
+ export declare function readModelDirectory(body: unknown, baseURL: string, source?: ModelSource): ModelDirectory;
56
+ export declare const MODEL_LISTING_MAX_BYTES: number;
57
+ export interface CachedDirectory {
58
+ readonly body: unknown;
59
+ readonly etag?: string;
60
+ readonly savedAtMs: number;
61
+ }
62
+ export declare function catalogCachePath(source?: ModelSource): string;
63
+ export declare function catalogETag(value: unknown): string | undefined;
64
+ export declare function readCatalogCache(path: string, sourceURL: string): Promise<CachedDirectory | undefined>;
65
+ export declare function writeCatalogCache(path: string, sourceURL: string, value: CachedDirectory): Promise<boolean>;
66
+ export { PROVIDER_ID, DISPLAY_NAME, FREE_PROVIDER_ID, FREE_DISPLAY_NAME, DEFAULT_BASE_URL, DEFAULT_FREE_BASE_URL } from './contracts.ts';
7
67
  export interface CatalogSnapshot {
8
- readonly details: ModelMetadata['details'];
68
+ readonly source: ModelSource;
69
+ readonly details: ModelDirectory['details'];
9
70
  readonly models: ReadonlyMap<string, Model<Api>>;
10
- /** Advertised ids with missing/unsupported metadata stay visible with a diagnostic. */
11
71
  readonly unavailable: ReadonlyMap<string, string>;
12
72
  readonly provider: Provider;
13
73
  readonly live: boolean;
14
- readonly metadataLive: boolean;
15
- /** Retained for explicit discovery; runtime callers may still use the last catalog. */
16
- readonly listingFailure?: unknown;
17
- readonly listingWarning?: string;
18
- readonly metadataFailure?: unknown;
19
- /** Last successful fetch or revalidation, not the time of a failed attempt. */
20
- readonly listingUpdatedAtMs?: number;
21
- readonly metadataUpdatedAtMs?: number;
74
+ readonly failure?: unknown;
75
+ readonly warning?: string;
76
+ readonly updatedAtMs?: number;
22
77
  readonly fetchedAtMs: number;
23
78
  }
24
- /** A valid empty listing means the gateway serves nothing; malformed replies are failures. */
25
- export declare function readLiveModelIds(body: unknown, onInvalidRows?: (warning: string) => void): readonly string[];
26
- /** Runtime requests reuse a snapshot; discovery revalidates it. Concurrent reads coalesce. */
79
+ /** One gateway owns its membership, disk cache, validator, refresh and failure backoff. */
27
80
  export declare class OpencodeGoCatalog {
28
81
  private readonly baseURL;
29
82
  private readonly refreshMs;
30
83
  private readonly onFallback;
31
- /** Kept for API compatibility; now reports unconfigured ids rather than hiding them. */
32
84
  private readonly onOmitted;
33
85
  private readonly onRefresh;
34
86
  private readonly fetcher?;
35
87
  private readonly onWarning?;
88
+ readonly source: ModelSource;
36
89
  private served;
37
90
  private pending;
38
- /** A cold runtime read can use disk metadata while the shared online refresh runs. */
39
- private cachedPending;
40
91
  private initialized;
41
- private readonly cachePath;
42
- private metadata;
43
- private metadataBody;
44
- private metadataETag;
45
- private metadataUpdatedAtMs;
46
- private failures;
92
+ private cached;
93
+ private startupCache;
47
94
  private refreshAtMs;
48
- constructor(baseURL: string, refreshMs: number, onFallback: (detail: {
95
+ private failures;
96
+ private readonly url;
97
+ private readonly cachePath;
98
+ constructor(baseURL: string, refreshMs: number, onFallback?: (detail: {
49
99
  url: string;
50
100
  error: unknown;
51
101
  kept: number;
52
- }) => void,
53
- /** Kept for API compatibility; now reports unconfigured ids rather than hiding them. */
54
- onOmitted: (ids: readonly string[]) => void, onRefresh?: () => void, fetcher?: typeof globalThis.fetch | undefined, onWarning?: ((warning: string) => void) | undefined);
102
+ }) => void, onOmitted?: (ids: readonly string[]) => void, onRefresh?: () => void, fetcher?: typeof globalThis.fetch | undefined, onWarning?: ((warning: string) => void) | undefined, source?: ModelSource);
55
103
  snapshot(force?: boolean, signal?: AbortSignal): Promise<CatalogSnapshot>;
56
- private restoreMetadata;
57
- private readSnapshot;
58
- private currentSnapshot;
59
- private startRefresh;
60
- /** Conditional HTTP requests save bandwidth while still checking for updated metadata. */
61
- private refreshMetadata;
62
- private persistMetadata;
63
- /** Gateway ids decide membership; online metadata decides how to call each model. */
104
+ private empty;
64
105
  private build;
65
- /** New or previously unconfigured ids get a fresh lookup even during the runtime TTL. */
106
+ private restore;
107
+ private refresh;
66
108
  forModel(id: string, signal?: AbortSignal): Promise<CatalogSnapshot>;
67
109
  }
68
- /** Explicit discovery always revalidates both sources, including during the runtime TTL. */
69
110
  export declare function discoverCatalogModels(catalog: OpencodeGoCatalog): Promise<readonly LlmDiscoveredModel[]>;
70
- /** Settings expose the same retained catalog as requests, with a failed-refresh diagnostic. */
71
- export declare function discoverSettingsModels(catalog: OpencodeGoCatalog): Promise<GoModelCatalog>;
111
+ export declare function discoverSettingsModels(catalog: OpencodeGoCatalog, freeCatalog?: OpencodeGoCatalog): Promise<GoModelCatalog>;
112
+ export declare class GoCatalogManager {
113
+ private readonly options;
114
+ private readonly current;
115
+ constructor(options: {
116
+ transport: ProxyTransport;
117
+ onFallback?: (detail: {
118
+ url: string;
119
+ error: unknown;
120
+ kept: number;
121
+ }) => void;
122
+ onOmitted?: (ids: readonly string[]) => void;
123
+ onRefresh?: () => void;
124
+ onWarning?: (warning: string) => void;
125
+ });
126
+ forConfig(config: OpencodeGoConfig, source?: ModelSource): OpencodeGoCatalog;
127
+ }
128
+ export declare class GoModelsService extends TypertRemoteService {
129
+ private readonly options;
130
+ constructor(ctx: Context, options: {
131
+ catalog: () => OpencodeGoCatalog;
132
+ freeCatalog?: () => OpencodeGoCatalog;
133
+ onRefresh?: () => void;
134
+ });
135
+ read(): Promise<GoModelCatalog>;
136
+ }
@@ -0,0 +1,18 @@
1
+ import type { AnalyticsExport, AnalyticsQuery, AnalyticsReport, GoAccount, GoUsage } from '../contracts.ts';
2
+ import { type en } from './presentation.ts';
3
+ export declare function historyNumber(value: string, locale?: string, compact?: boolean): string;
4
+ /** Keep micro-cents exact through rounding: one dollar is 100,000,000 units. */
5
+ export declare function historyMoney(value: string, locale?: string): string;
6
+ export interface AnalyticsDialogProps {
7
+ open: boolean;
8
+ onClose: () => void;
9
+ readAnalytics: (query: AnalyticsQuery, signal?: AbortSignal) => Promise<AnalyticsReport>;
10
+ exportAnalytics?: (query: AnalyticsQuery, signal?: AbortSignal) => Promise<AnalyticsExport>;
11
+ readQuota?: (ref: string) => Promise<GoUsage>;
12
+ accounts: readonly GoAccount[];
13
+ activeRef: string;
14
+ contextKey?: string | number;
15
+ t: (key: keyof typeof en) => string;
16
+ getLocale?: () => string;
17
+ }
18
+ export declare function AnalyticsDialog(props: AnalyticsDialogProps): import("react").JSX.Element;
@@ -1,12 +1,46 @@
1
+ import { type en } from './presentation.ts';
2
+ import type { GoAccountsActions, GoAccountsState, OpencodeGoModelLimit, OpencodeGoModelLimits, OpencodeGoModels, OpencodeGoSectionFace } from './controller.ts';
3
+ import { type ModelSource } from '../contracts.ts';
4
+ import type { InjectFace } from '@deepseek-ai/dsh-client-ui-slots';
5
+ export declare function HintMark(props: {
6
+ hint: string;
7
+ }): import("react").JSX.Element;
8
+ export declare function HintText(props: {
9
+ id: string;
10
+ hint: string;
11
+ }): import("react").JSX.Element;
12
+ type AccountTranslate = (key: keyof typeof en, params?: Record<string, unknown>) => string;
1
13
  /**
2
- * The OpenCode Go settings page: provider activation, accounts and credentials,
3
- * available models and capacities, then advanced tuning. Account operations
4
- * apply immediately; tuning fields use the page's save/discard actions.
14
+ * The account card: a folded header that summarizes the set, and one row per
15
+ * account inside. Rows keep the identity, key state, rolling quota and its reset
16
+ * countdown; everything else opens under the row. The handle is the drag source —
17
+ * dragging it, or the arrow keys on it, reorders the list, and the first row is
18
+ * the preferred account. Every row is read in the same pass, so the one refresh
19
+ * stamp belongs to the card and sits in its header.
5
20
  */
6
- import type { InjectFace } from '@deepseek-ai/dsh-client-ui-slots';
7
- import type { OpencodeGoSectionFace } from './section-controller.ts';
8
- import type { en } from './locales.ts';
9
- export type { OpencodeGoSectionState } from './section-controller.ts';
21
+ export declare function AccountsCard({ state, actions, writable, t, locale }: {
22
+ state: GoAccountsState;
23
+ actions: GoAccountsActions;
24
+ writable: boolean;
25
+ t: AccountTranslate;
26
+ locale?: string;
27
+ }): import("react").JSX.Element;
28
+ type ModelTranslate = (key: keyof typeof en, params?: Record<string, unknown>) => string;
29
+ export declare function hasCapacityOverride(limit: OpencodeGoModelLimit | null | undefined): boolean;
30
+ /** Per-model switches apply immediately; capacity edits stay in the staged form. */
31
+ export declare function ModelEditor({ source, models, draft, modelVisibility, t, locale, disabled, visibilitySaving, onEdit, onModelEnabled }: {
32
+ source?: ModelSource;
33
+ models: OpencodeGoModels;
34
+ draft: OpencodeGoModelLimits;
35
+ modelVisibility: Readonly<Record<string, boolean>>;
36
+ t: ModelTranslate;
37
+ locale?: string;
38
+ disabled: boolean;
39
+ visibilitySaving: boolean;
40
+ onEdit: (next: OpencodeGoModelLimits) => void;
41
+ onModelEnabled: (id: string, enabled: boolean) => void;
42
+ }): import("react").JSX.Element;
43
+ export type { OpencodeGoSectionState } from './controller.ts';
10
44
  /** Section copy lookup, including the optional `{name}` template params. */
11
45
  type SectionTranslate = (key: keyof typeof en, params?: Record<string, unknown>) => string;
12
46
  /** Injected dependencies of {@link OpencodeGoSection} (slot `inject`). */
@@ -1,16 +1,25 @@
1
1
  import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
2
2
  import type { ModelDirectoryState } from '@deepseek-ai/dsh-client-ui-model-selection/client';
3
- import { type GoUsage } from '../usage-contract.ts';
4
- import type { SettingsScope } from './settings.ts';
5
- import type { OpencodeGoSettings } from './section-controller.ts';
3
+ import { type GoUsage, type AnalyticsQuery, type AnalyticsReport, type AnalyticsExport } from '../contracts.ts';
4
+ import type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client';
5
+ import type { OpencodeGoSettings } from './controller.ts';
6
6
  export interface UsagePillProps {
7
7
  directory: SnapshotStore<ModelDirectoryState>;
8
- settings: SettingsScope<OpencodeGoSettings>;
8
+ settings: ConfigForm<OpencodeGoSettings>;
9
9
  readUsage: () => Promise<GoUsage>;
10
+ readAccountUsage?: (ref: string) => Promise<GoUsage>;
11
+ /** Optional so an embedded/test render can omit the dashboard. */
12
+ readAnalytics?: (query: AnalyticsQuery, signal?: AbortSignal) => Promise<AnalyticsReport>;
13
+ exportAnalytics?: (query: AnalyticsQuery, signal?: AbortSignal) => Promise<AnalyticsExport>;
10
14
  t: (key: string) => string;
11
15
  getLocale?: () => string;
12
16
  credentialChanges?: SnapshotStore<number>;
13
17
  selectAccount?: (ref: string) => Promise<boolean>;
14
18
  }
15
- /** Only a visible, enabled pill mounts the usage poller. */
16
- export declare function UsagePill({ directory, settings, credentialChanges, ...props }: UsagePillProps): import("react").JSX.Element | null;
19
+ /** A root sidebar entry receives its width mode from the host slot owner. */
20
+ export type SidebarQuotaProps = Omit<UsagePillProps, 'directory'> & {
21
+ wide: boolean;
22
+ };
23
+ /** Only a visible, enabled input indicator mounts the usage poller. */
24
+ export declare function UsagePill({ directory, ...props }: UsagePillProps): import("react").JSX.Element;
25
+ export declare function SidebarQuota({ wide, ...props }: SidebarQuotaProps): import("react").JSX.Element;