@vibedev-si/dsh-vibedev 0.3.0 → 0.3.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/lib/pricing.d.ts CHANGED
@@ -4,27 +4,45 @@
4
4
  * per-second video prices times billed seconds, where billed seconds are the
5
5
  * output length plus the summed reference video length, rounded up once.
6
6
  * Estimates are for the user's information; the gateway's receipt is the charge.
7
+ *
8
+ * A model without a price is "not priced" (未定价), never free: only a price the
9
+ * catalog states as zero is shown as ¥0.
7
10
  * @module dsh-vibedev/pricing
8
11
  */
9
- import type { MediaModel } from './gateway/catalog.js';
12
+ import type { MediaKind, MediaModel, PriceUnit } from './gateway/catalog.js';
10
13
  /** One estimate. */
11
14
  export interface Estimate {
12
15
  readonly amountCny: number;
13
16
  /** How it was reached, such as `¥0.99/s × 5 s`. */
14
17
  readonly basis: string;
15
18
  }
19
+ /** Text in both languages the plugin speaks. */
20
+ export interface Bilingual {
21
+ readonly en: string;
22
+ readonly zh: string;
23
+ }
24
+ /** Shown wherever the catalog gives no price. */
25
+ export declare const UNPRICED: Bilingual;
16
26
  /**
17
- * Format an amount in yuan.
27
+ * Format an amount in yuan: two decimals, more when a small unit price needs them (`¥0.015`).
18
28
  * @param amount - the amount.
19
29
  * @returns `¥4.95`.
20
30
  */
21
31
  export declare function yuan(amount: number): string;
22
32
  /**
23
- * A one-line price for listings: `¥0.10 per image`, `¥0.99/s (720p)`.
33
+ * The unit after a price: `/s`, `/原始秒`, `/次`.
34
+ * @param unit - the price unit.
35
+ * @param kind - the kind of model, which names a generation (an image, a video, a request).
36
+ * @returns the suffix in both languages.
37
+ */
38
+ export declare function unitSuffix(unit: PriceUnit, kind: MediaKind): Bilingual;
39
+ /**
40
+ * A one-line price for listings: `¥0.10 per image`, `¥0.99/s (720p)`; `not priced` without a price.
24
41
  * @param model - the model.
25
- * @returns the price, or undefined when the catalog gives none.
42
+ * @param lang - the language.
43
+ * @returns the price line.
26
44
  */
27
- export declare function describePrice(model: MediaModel): string | undefined;
45
+ export declare function describePrice(model: MediaModel, lang?: keyof Bilingual): string;
28
46
  /**
29
47
  * Estimate an image request.
30
48
  * @param model - the image model.
@@ -41,9 +59,27 @@ export declare function estimateImages(model: MediaModel, count: number): Estima
41
59
  * @returns the estimate, or undefined without a price.
42
60
  */
43
61
  export declare function estimateVideo(model: MediaModel, duration: number | undefined, resolution: string | undefined, referenceMs?: number): Estimate | undefined;
62
+ /** What an audio request costs, as far as it can be known before it runs. */
63
+ export interface AudioQuote {
64
+ /** The catalog states a price. */
65
+ readonly priced: boolean;
66
+ readonly unit?: PriceUnit;
67
+ readonly unitPriceCny?: number;
68
+ /**
69
+ * The amount, when it is known before the request runs: per generation, or
70
+ * per minute of an input whose length was measured. Speech billed per
71
+ * original second is known only once the provider reports that length.
72
+ */
73
+ readonly amountCny?: number;
74
+ /** The unit price: `¥0.50/次`, `¥0.02/原始秒`, `¥0.30/分钟`, or `未定价`. */
75
+ readonly label: Bilingual;
76
+ /** How the charge is reached. */
77
+ readonly basis: Bilingual;
78
+ }
44
79
  /**
45
- * Estimate a music or podcast request.
46
- * @param model - the audio model.
47
- * @returns the estimate, or undefined without a price.
80
+ * Quote an audio request: music, podcast and speech generation, or a transcription.
81
+ * @param model - the audio or transcription model.
82
+ * @param inputSeconds - for a transcription, the measured length of the input, when known.
83
+ * @returns the quote; `priced: false` (未定价) when the catalog gives no usable price.
48
84
  */
49
- export declare function estimateAudio(model: MediaModel): Estimate | undefined;
85
+ export declare function quoteAudio(model: MediaModel, inputSeconds?: number): AudioQuote;
package/lib/runtime.d.ts CHANGED
@@ -18,7 +18,22 @@ import type { LoadedMedia } from './media/sources.js';
18
18
  import type { TaskStore } from './tasks/store.js';
19
19
  import type { TaskTracker } from './tasks/tracker.js';
20
20
  /** The model a setting can pin per kind of output. */
21
- export type ModelSlot = 'image' | 'video' | 'music' | 'podcast' | 'transcription';
21
+ export type ModelSlot = 'image' | 'video' | 'music' | 'podcast' | 'speech' | 'transcription';
22
+ /**
23
+ * Whether a model serves a slot. Audio models serve the kind their catalog
24
+ * entry declares, and only that: an undeclared kind serves none.
25
+ * @param model - the model.
26
+ * @param slot - the slot.
27
+ * @returns whether the model can be chosen for it.
28
+ */
29
+ export declare function servesSlot(model: MediaModel, slot: ModelSlot): boolean;
30
+ /**
31
+ * The model a name refers to: its id, else one of its aliases (case-insensitive).
32
+ * @param models - the catalog.
33
+ * @param wanted - the id or alias.
34
+ * @returns the model, or undefined.
35
+ */
36
+ export declare function modelNamed(models: readonly MediaModel[], wanted: string): MediaModel | undefined;
22
37
  /** Live settings (the plugin's volatile config). */
23
38
  export interface MediaSettings {
24
39
  /** Output folder, relative to the workspace (or absolute). */
@@ -94,6 +109,14 @@ export declare class MediaRuntime {
94
109
  * @returns the model.
95
110
  */
96
111
  pickModel(kind: MediaKind, slot: ModelSlot, requested: string | undefined, accept?: (model: MediaModel) => boolean, signal?: AbortSignal): Promise<MediaModel>;
112
+ /**
113
+ * The model a name refers to, whatever its kind.
114
+ * @param requested - an id or alias.
115
+ * @param signal - cancels the catalog request.
116
+ * @returns the model.
117
+ * @throws {@link MediaError} when the account has no such model.
118
+ */
119
+ findModel(requested: string, signal?: AbortSignal): Promise<MediaModel>;
97
120
  /**
98
121
  * The workspace of the calling session.
99
122
  * @param call - the tool call or host call.
package/lib/service.d.ts CHANGED
@@ -6,9 +6,17 @@
6
6
  * follower that saves the result — with the caller naming the workspace and
7
7
  * where results go. The caller has already shown the price and the user chose
8
8
  * to go ahead, so the spending confirmation setting does not ask again.
9
+ *
10
+ * Every task, video or audio, is read the same way: {@link MediaHostService.task}
11
+ * (what is recorded), {@link MediaHostService.refreshTask} (ask the gateway again:
12
+ * fresh links, settlement — a query only, it never submits),
13
+ * {@link MediaHostService.onTask} (each change) and
14
+ * {@link MediaHostService.result} (the files to play or download).
9
15
  * @module dsh-vibedev/service
10
16
  */
17
+ import type { AudioForm, AudioRequest } from './audio/request.js';
11
18
  import type { MediaModel } from './gateway/catalog.js';
19
+ import type { AudioQuote } from './pricing.js';
12
20
  import type { MediaRuntime } from './runtime.js';
13
21
  import type { TaskRecord, TaskStatus } from './tasks/store.js';
14
22
  import type { ImageRequest } from './tools/image.js';
@@ -22,24 +30,42 @@ export interface HostTarget {
22
30
  /** File-name stem of the results. */
23
31
  readonly stem: string;
24
32
  }
33
+ /** One produced file, as host callers see it. */
34
+ export interface MediaOutputView {
35
+ /** Where it was saved; absent while it could not be downloaded. */
36
+ readonly path?: string;
37
+ /** The gateway's link (signed; it expires — {@link MediaHostService.result} renews it). */
38
+ readonly url?: string;
39
+ readonly contentType?: string;
40
+ readonly title?: string;
41
+ /** Playback length. */
42
+ readonly durationSeconds?: number;
43
+ /** The original length it is billed on (speech), when it differs from playback. */
44
+ readonly originalSeconds?: number;
45
+ }
25
46
  /** A video or audio task, as host callers see it. */
26
47
  export interface MediaTaskView {
27
48
  readonly id: string;
28
49
  readonly kind: TaskRecord['kind'];
50
+ /** For audio: music, podcast or speech. */
51
+ readonly audioKind?: string;
29
52
  readonly model: string;
30
53
  readonly status: TaskStatus;
31
54
  readonly progress?: string;
32
- readonly outputs?: readonly {
33
- readonly path?: string;
34
- readonly url?: string;
35
- readonly durationSeconds?: number;
36
- }[];
55
+ readonly outputs?: readonly MediaOutputView[];
37
56
  readonly error?: {
38
57
  readonly code: string;
39
58
  readonly message: string;
40
59
  };
41
60
  readonly estimatedCny?: string;
42
61
  readonly chargedCny?: string;
62
+ /**
63
+ * `pending`: the result is there, the charge is still being settled (it is
64
+ * never generated again); `settled`: `chargedCny` is final.
65
+ */
66
+ readonly settlement?: 'pending' | 'settled';
67
+ /** How it is billed: the unit, the unit price, and the billed length once known. */
68
+ readonly billing?: TaskRecord['billing'];
43
69
  readonly createdAt: number;
44
70
  readonly updatedAt: number;
45
71
  }
@@ -49,11 +75,26 @@ export declare class MediaHostService {
49
75
  constructor(runtime: MediaRuntime, version: string);
50
76
  private call;
51
77
  /**
52
- * The media models this account can use (cached briefly).
78
+ * The media models this account can use (cached briefly; renewed after a sign-in, sign-out or account switch).
53
79
  * @param signal - cancels the request.
54
80
  * @returns the models in catalog order.
55
81
  */
56
82
  models(signal?: AbortSignal): Promise<readonly MediaModel[]>;
83
+ /**
84
+ * The forms to show for the audio models this account can use: one per
85
+ * model that declares what it makes, with only the fields it takes, their
86
+ * declared choices and limits, and its price.
87
+ * @param signal - cancels the catalog request.
88
+ * @returns the forms, in catalog order.
89
+ */
90
+ audioForms(signal?: AbortSignal): Promise<readonly AudioForm[]>;
91
+ /**
92
+ * The price of one audio or transcription model: `¥0.50/次`, `¥0.02/原始秒`, `¥0.30/分钟`, or 未定价.
93
+ * @param model - the model id or alias.
94
+ * @param signal - cancels the catalog request.
95
+ * @returns the quote.
96
+ */
97
+ audioPrice(model: string, signal?: AbortSignal): Promise<AudioQuote>;
57
98
  /**
58
99
  * Generate images now and save them.
59
100
  * @param request - what to generate.
@@ -84,11 +125,44 @@ export declare class MediaHostService {
84
125
  */
85
126
  startVideo(request: VideoRequest, target: HostTarget, signal: AbortSignal): Promise<MediaTaskView>;
86
127
  /**
87
- * A task's current state.
128
+ * Submit music, a podcast episode or speech. Fields are checked against
129
+ * what the model declares before anything is uploaded or charged; speech
130
+ * references are uploaded to the gateway media library first.
131
+ *
132
+ * One user operation, one task: pass the same `operationId` when the same
133
+ * click is retried and the task already recorded under it is returned —
134
+ * nothing is submitted twice. Without one, every call is a new operation.
135
+ * @param request - what to generate.
136
+ * @param target - the workspace and where the audio goes.
137
+ * @param signal - cancels the preparation and the submission.
138
+ * @returns the task.
139
+ */
140
+ startAudio(request: AudioRequest, target: HostTarget, signal: AbortSignal): Promise<MediaTaskView>;
141
+ private submit;
142
+ /**
143
+ * A task's current state, as recorded (no request to the gateway).
88
144
  * @param id - the task id.
89
145
  * @returns the task, or `undefined` when there is none.
90
146
  */
91
147
  task(id: string): Promise<MediaTaskView | undefined>;
148
+ /**
149
+ * Ask the gateway about a task again — a query, never a submission: a
150
+ * finished task gets fresh links and its missing files are downloaded
151
+ * again, and a pending settlement is read again. A running task is followed.
152
+ * @param id - the task id.
153
+ * @param signal - cancels the query.
154
+ * @returns the task after the query, or `undefined` when there is none.
155
+ */
156
+ refreshTask(id: string, signal?: AbortSignal): Promise<MediaTaskView | undefined>;
157
+ /**
158
+ * The files of a finished task, ready to play or download: saved files by
159
+ * path, and links renewed by a query when one is needed (a missing file, an
160
+ * expired link). Never generates again.
161
+ * @param id - the task id.
162
+ * @param signal - cancels the query.
163
+ * @returns the outputs, or `undefined` while the task has none.
164
+ */
165
+ result(id: string, signal?: AbortSignal): Promise<readonly MediaOutputView[] | undefined>;
92
166
  /**
93
167
  * Hear about every change to one task.
94
168
  * @param id - the task id.
@@ -13,11 +13,18 @@ export interface RemoteOutput {
13
13
  readonly url?: string;
14
14
  readonly contentType?: string;
15
15
  readonly title?: string;
16
+ /** Playback length. */
16
17
  readonly durationSeconds?: number;
18
+ /** The provider's original length this output is billed on, when it differs from playback (speech). */
19
+ readonly originalSeconds?: number;
17
20
  }
18
21
  /** A task's state. */
19
22
  export interface RemoteTask {
20
23
  readonly id: string;
24
+ /**
25
+ * `completed` also covers `settlement_pending`: the result exists and is
26
+ * saved, only the charge is still being settled — it is never generated again.
27
+ */
21
28
  readonly state: 'pending' | 'completed' | 'failed';
22
29
  /** The gateway's own status word. */
23
30
  readonly status: string;
@@ -31,6 +38,12 @@ export interface RemoteTask {
31
38
  readonly estimatedCny?: string;
32
39
  /** Settled charge (CNY); absent until the gateway settles, which is not the same as free. */
33
40
  readonly chargedCny?: string;
41
+ /** Whether the charge of a finished task has settled; absent when the gateway does not say. */
42
+ readonly settlement?: 'pending' | 'settled';
43
+ /** The billed original length of the whole task, in seconds (speech). */
44
+ readonly billedOriginalSeconds?: number;
45
+ /** The billed input length, in minutes (transcription). */
46
+ readonly billedMinutes?: number;
34
47
  readonly outputs: readonly RemoteOutput[];
35
48
  }
36
49
  /**
@@ -27,7 +27,10 @@ export interface TaskOutput {
27
27
  readonly contentType?: string;
28
28
  readonly bytes?: number;
29
29
  readonly title?: string;
30
+ /** Playback length. */
30
31
  readonly durationSeconds?: number;
32
+ /** The original length this output is billed on (speech), when the gateway reports it. */
33
+ readonly originalSeconds?: number;
31
34
  }
32
35
  /** One task. */
33
36
  export interface TaskRecord {
@@ -59,6 +62,20 @@ export interface TaskRecord {
59
62
  };
60
63
  readonly estimatedCny?: string;
61
64
  readonly chargedCny?: string;
65
+ /**
66
+ * Whether the charge of a finished task has settled. `pending`: the result is
67
+ * saved and is never generated again; only the charge is still to come.
68
+ */
69
+ readonly settlement?: 'pending' | 'settled';
70
+ /** What an audio task makes (music, podcast or speech). */
71
+ readonly audioKind?: string;
72
+ /** How the task is billed, and the billed length once the gateway reports it. */
73
+ readonly billing?: {
74
+ readonly unit?: string;
75
+ readonly unitPriceCny?: string;
76
+ readonly originalSeconds?: number;
77
+ readonly minutes?: number;
78
+ };
62
79
  readonly finishedAt?: number;
63
80
  }
64
81
  /**
@@ -143,8 +143,21 @@ export declare class TaskTracker {
143
143
  * @returns how long to wait before the next try, or undefined once the task has been ended.
144
144
  */
145
145
  private afterFailure;
146
+ /** The money and billing facts of a gateway answer, merged into what the record already knows. */
147
+ private moneyOf;
146
148
  /** Record what the gateway says about a task; save the outputs of a finished one. */
147
149
  private apply;
150
+ /**
151
+ * Ask the gateway about a task again, by query only: a finished task gets
152
+ * fresh links (signed links expire), files that are missing locally are
153
+ * downloaded again, and a pending settlement is read again. Nothing is ever
154
+ * submitted from here, so a failed query or download cannot create a task.
155
+ * A task still running is followed as usual.
156
+ * @param id - the local task id.
157
+ * @param signal - cancels the query.
158
+ * @returns the task after the query.
159
+ */
160
+ refresh(id: string, signal?: AbortSignal): Promise<TaskRecord>;
148
161
  /**
149
162
  * Save every output not saved yet, recording each one as it lands. A
150
163
  * shutdown mid-download throws, so the task stays open and is resumed.
@@ -1,6 +1,7 @@
1
1
  /**
2
- * `audio_generate`: a song or a podcast episode, as a background task whose
3
- * results are saved in the workspace.
2
+ * `audio_generate`: music, a podcast episode or speech, as a background task
3
+ * whose results are saved in the workspace. Every field is checked against
4
+ * what the chosen model declares (see `audio/request`).
4
5
  * @module dsh-vibedev/tools/audio
5
6
  */
6
7
  import type { ToolDefinition } from '@deepseek-ai/dsh-tools';
@@ -4,7 +4,14 @@
4
4
  * @module dsh-vibedev/tools/models
5
5
  */
6
6
  import type { ToolDefinition } from '@deepseek-ai/dsh-tools';
7
+ import type { MediaModel } from '../gateway/catalog.js';
7
8
  import type { MediaRuntime } from '../runtime.js';
9
+ /**
10
+ * What an audio model takes, from its declaration: the fields, speech references, output formats and sample rates.
11
+ * @param model - an audio or transcription model.
12
+ * @returns one line, or undefined when nothing is declared.
13
+ */
14
+ export declare function describeAudioModel(model: MediaModel): string | undefined;
8
15
  /**
9
16
  * Build the tool.
10
17
  * @param runtime - the media runtime.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibedev-si/dsh-vibedev",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "VibeDev 账号与模型:在 DeepSeek Harness 里登录 VibeDev,与 DeepSeek 账号并存,使用 VibeDev 网关的模型(Claude、GPT 等),并生成图片、视频、音乐和播客 · VibeDev account and models for DeepSeek Harness: sign in to VibeDev next to the DeepSeek account and use the VibeDev gateway's models (Claude, GPT and more), plus image, video, music and podcast generation",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",