@hypit/hypit 0.1.7 → 0.1.9
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.md +15 -4
- package/dist/public/endpoint-kit.d.ts +1 -1
- package/dist/public/runtime-kit.d.ts +3 -1
- package/examples/provider-package/README.md +12 -0
- package/examples/provider-package/packages/provider-images/src/provider.ts +37 -8
- package/package.json +1 -1
- package/packages/cli/README.md +35 -0
- package/packages/cli/src/arguments.ts +12 -1
- package/packages/cli/src/command-hint.ts +20 -0
- package/packages/cli/src/commands/environment.ts +39 -18
- package/packages/cli/src/commands/execution.ts +34 -18
- package/packages/cli/src/commands/results.ts +8 -3
- package/packages/cli/src/machine-view.ts +4 -2
- package/packages/cli/src/main.ts +25 -23
- package/packages/cli/src/observation.ts +7 -2
- package/packages/cli/src/output.ts +8 -0
- package/packages/cli/src/usage-error.ts +8 -0
- package/packages/cli/src/view.ts +4 -1
- package/packages/driver-node/README.md +5 -0
- package/packages/driver-node/src/driver.ts +20 -15
- package/packages/endpoint-kit/README.md +11 -2
- package/packages/endpoint-kit/src/index.ts +1 -1
- package/packages/generation/README.md +10 -0
- package/packages/provider-hypihub/README.md +41 -6
- package/packages/provider-hypihub/src/errors.ts +61 -0
- package/packages/provider-hypihub/src/mapping.ts +10 -25
- package/packages/provider-hypihub/src/oauth.ts +4 -1
- package/packages/provider-hypihub/src/provider.ts +79 -74
- package/packages/provider-hypihub/src/routes.ts +24 -3
- package/packages/provider-hypihub/src/upload.ts +8 -18
- package/packages/provider-whisperx-local/README.md +7 -1
- package/packages/provider-whisperx-local/src/program.ts +2 -0
- package/packages/runtime-host-node/src/index.ts +4 -0
- package/packages/runtime-kit/README.md +3 -0
- package/packages/runtime-kit/src/index.ts +2 -0
- package/packages/runtime-local/README.md +17 -0
- package/packages/runtime-local/package.json +2 -1
- package/packages/runtime-local/src/program-lock.ts +40 -0
- package/packages/runtime-local/src/programs.ts +156 -79
- package/packages/video-cli/README.md +33 -6
- package/packages/video-cli/src/cli.ts +4 -1
- package/packages/video-cli/src/creation.ts +7 -2
- package/packages/video-cli/src/index.ts +2 -0
- package/packages/video-cli/src/version.ts +90 -0
- package/services/whisperx/README.md +10 -3
- package/services/whisperx/src/hypit_whisperx_service/engine.py +19 -1
|
@@ -9,6 +9,8 @@ type ProgramStateView = {
|
|
|
9
9
|
readonly detail?: string;
|
|
10
10
|
readonly pid?: number;
|
|
11
11
|
readonly logPath?: string;
|
|
12
|
+
readonly installationLogPath?: string;
|
|
13
|
+
readonly errorLogPath?: string;
|
|
12
14
|
};
|
|
13
15
|
type AttentionView = { readonly message: string; readonly action?: string };
|
|
14
16
|
|
|
@@ -18,12 +20,12 @@ export type OperationalMachineView =
|
|
|
18
20
|
| { readonly format: "hypit.cli-runtime-selection@1"; readonly selected: boolean; readonly removed?: boolean; readonly profile?: string; readonly project?: string }
|
|
19
21
|
| { readonly format: "hypit.cli-paths@1"; readonly project: string; readonly projectState: string; readonly profileSource: "argument" | "project" | "none"; readonly selectionFile: string; readonly profile?: string; readonly runtimeData?: string; readonly hostState: string; readonly machinePackages: string; readonly distribution?: string }
|
|
20
22
|
| { readonly format: "hypit.cli-package@1"; readonly action: "install" | "status"; readonly package: string; readonly ready: boolean }
|
|
21
|
-
| { readonly format: "hypit.cli-programs@1"; readonly action: "up" | "down" | "status"; readonly ready: boolean; readonly programCount: number; readonly readyCount: number; readonly programs: readonly ProgramStateView[]; readonly omittedPrograms?: number }
|
|
23
|
+
| { readonly format: "hypit.cli-programs@1"; readonly action: "up" | "down" | "status"; readonly ok: boolean; readonly ready: boolean; readonly programCount: number; readonly readyCount: number; readonly programs: readonly ProgramStateView[]; readonly omittedPrograms?: number }
|
|
22
24
|
| { readonly format: "hypit.cli-runtime-up@1"; readonly ready: boolean; readonly worker: string; readonly preparedPackages: number; readonly programs: { readonly total: number; readonly ready: number; readonly items: readonly ProgramStateView[] } }
|
|
23
25
|
| { readonly format: "hypit.cli-runtime-logs@1"; readonly lines: readonly string[]; readonly totalLines: number; readonly omittedLines: number; readonly path?: string }
|
|
24
26
|
| { readonly format: "hypit.cli-runtime-down@1"; readonly worker: string }
|
|
25
27
|
| { readonly format: "hypit.cli-runtime-status@1"; readonly ready: boolean; readonly attention: boolean; readonly worker: { readonly state: string; readonly configuration?: string }; readonly builds: Readonly<Record<string, number>>; readonly programs: { readonly total: number; readonly ready: number; readonly unavailable: readonly ProgramStateView[] }; readonly capacity: { readonly active: number } }
|
|
26
|
-
| { readonly format: "hypit.cli-auth-status@1"; readonly endpoint: string; readonly credentials: readonly { readonly endpoint: string; readonly slot: string; readonly label: string; readonly kind: string; readonly configured: boolean; readonly writable: boolean }[]; readonly omittedCredentials?: number }
|
|
28
|
+
| { readonly format: "hypit.cli-auth-status@1"; readonly endpoint: string; readonly credentials: readonly { readonly endpoint: string; readonly slot: string; readonly label: string; readonly kind: string; readonly configured: boolean; readonly writable: boolean; readonly acquisition?: { readonly kind: string; readonly authorizationEndpoint: string } }[]; readonly omittedCredentials?: number }
|
|
27
29
|
| { readonly format: "hypit.cli-auth-change@1"; readonly endpoint: string; readonly slot: string; readonly configured: boolean; readonly changed?: boolean }
|
|
28
30
|
| { readonly format: "hypit.cli-builds@1"; readonly builds: readonly { readonly id: string; readonly createdAt: string; readonly title?: string; readonly outcome: string; readonly run?: string; readonly targetCount: number; readonly targets?: readonly string[]; readonly omittedTargets?: number; readonly outputCount: number }[]; readonly next?: string }
|
|
29
31
|
| { readonly format: "hypit.cli-history@1"; readonly output: string; readonly source?: string; readonly entries: readonly { readonly build: string; readonly title?: string; readonly createdAt: string; readonly outcome: string; readonly output: CliOutputView }[]; readonly next?: string }
|
package/packages/cli/src/main.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { createPlanOutput, createPricingOutput, writeCliHelp, writeCliOutput } f
|
|
|
17
17
|
import type { CliIo, CliMachineView } from "./output.js";
|
|
18
18
|
import { parseCommand } from "./arguments.js";
|
|
19
19
|
import type { CliCommand, RuntimeOption } from "./command.js";
|
|
20
|
+
import { commandHint } from "./command-hint.js";
|
|
20
21
|
import { assertPlannedRequests, assertPreflight, createCatalogDescriptor, describePlanNeeds, describePlanPricing, describePlanProviders, evaluatePlanNeeds, preflightPlan } from "./build-planning.js";
|
|
21
22
|
import { buildProgressLines, observeBuild } from "./observation.js";
|
|
22
23
|
import { isProjectResultCommand, runProjectResultCommand } from "./commands/results.js";
|
|
@@ -62,7 +63,8 @@ export async function runCli(
|
|
|
62
63
|
distribution: CliDistribution,
|
|
63
64
|
): Promise<void> {
|
|
64
65
|
if (argv.length === 0 || argv[0] === "help" || argv.includes("--help")) {
|
|
65
|
-
const topic = argv[0] === "help" ? argv[1] : argv
|
|
66
|
+
const topic = argv[0] === "help" ? argv[1] : argv[0] === "--help" ? undefined
|
|
67
|
+
: argv.includes("--help") ? argv[0] : undefined;
|
|
66
68
|
writeCliHelp(io, topic);
|
|
67
69
|
return;
|
|
68
70
|
}
|
|
@@ -179,14 +181,11 @@ export async function runCli(
|
|
|
179
181
|
|
|
180
182
|
let runtimeProfile = acceptsRuntimeContext(args) ? args.runtimeProfile : undefined;
|
|
181
183
|
let runtimeSelectionFile: string | undefined;
|
|
182
|
-
const runtimeWasExplicit = runtimeProfile !== undefined;
|
|
183
|
-
let runtimeNeedsHint = runtimeWasExplicit;
|
|
184
184
|
if (acceptsRuntimeContext(args) && runtimeProfile === undefined && args.command !== "logs") {
|
|
185
185
|
const selected = await findRuntimeProfile(await commandProjectRoot());
|
|
186
186
|
if (selected !== undefined) {
|
|
187
187
|
runtimeProfile = selected.profile;
|
|
188
188
|
runtimeSelectionFile = selected.selectionFile;
|
|
189
|
-
runtimeNeedsHint = false;
|
|
190
189
|
}
|
|
191
190
|
}
|
|
192
191
|
const runtimeController = async (profile: string): Promise<CliRuntimeController> => {
|
|
@@ -227,6 +226,7 @@ export async function runCli(
|
|
|
227
226
|
if (isExecutionCommand(args)) {
|
|
228
227
|
await runExecutionCommand({
|
|
229
228
|
args,
|
|
229
|
+
projectRoot: await commandProjectRoot(),
|
|
230
230
|
runtimeProfile,
|
|
231
231
|
io,
|
|
232
232
|
runtimeHost,
|
|
@@ -346,6 +346,7 @@ export async function runCli(
|
|
|
346
346
|
if (runtimeProfile === undefined) {
|
|
347
347
|
throw new Error("build requires a Runtime; run hypit runtime init, select one with runtime use, or pass --runtime <profile>");
|
|
348
348
|
}
|
|
349
|
+
const commandScope = { projectRoot: projectResultsRoot, runtimeProfile: resolve(runtimeProfile) };
|
|
349
350
|
const buildResults = await projectResults(projectResultsRoot);
|
|
350
351
|
let loadedRun;
|
|
351
352
|
try {
|
|
@@ -434,7 +435,7 @@ export async function runCli(
|
|
|
434
435
|
]),
|
|
435
436
|
].join(" · ");
|
|
436
437
|
if (args.follow && "view" in built && !args.presentation.json) {
|
|
437
|
-
const acceptedView = buildStatusView({ id: built.id, runtime: built.view });
|
|
438
|
+
const acceptedView = buildStatusView({ id: built.id, runtime: built.view, commandScope });
|
|
438
439
|
const targets = built.view.targets.slice(0, args.limit);
|
|
439
440
|
writeOperational({
|
|
440
441
|
format: "hypit.cli-build@1",
|
|
@@ -451,15 +452,15 @@ export async function runCli(
|
|
|
451
452
|
built = await observeBuild(runtime, built, {
|
|
452
453
|
...(args.maxWaitMs === undefined ? {} : { maxWaitMs: args.maxWaitMs }),
|
|
453
454
|
controller,
|
|
455
|
+
commandScope,
|
|
454
456
|
readResult: async () => await buildResults.repository.read(built.id),
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
}),
|
|
457
|
+
onProgress: (progress) => {
|
|
458
|
+
const report = io.writeProgress ?? (args.presentation.json ? undefined : io.write);
|
|
459
|
+
for (const line of buildProgressLines(progress, {
|
|
460
|
+
verbose: args.presentation.verbose,
|
|
461
|
+
limit: args.limit,
|
|
462
|
+
})) report?.(`${line}\n`);
|
|
463
|
+
},
|
|
463
464
|
});
|
|
464
465
|
}
|
|
465
466
|
const finished = "completion" in built;
|
|
@@ -490,6 +491,7 @@ export async function runCli(
|
|
|
490
491
|
});
|
|
491
492
|
const buildView = buildStatusView({
|
|
492
493
|
id: built.id,
|
|
494
|
+
commandScope,
|
|
493
495
|
...(activeView === undefined ? {} : { runtime: activeView }),
|
|
494
496
|
...(finishedResult === undefined ? {} : { result: finishedResult }),
|
|
495
497
|
verbose: args.presentation.verbose,
|
|
@@ -500,7 +502,7 @@ export async function runCli(
|
|
|
500
502
|
? buildView
|
|
501
503
|
: { ...buildView, title: args.title },
|
|
502
504
|
};
|
|
503
|
-
const
|
|
505
|
+
const resultScope = { projectRoot: projectResultsRoot };
|
|
504
506
|
const resultTargets = finishedResult?.targets.flatMap((name) => {
|
|
505
507
|
const output = finishedResult.outputs[name];
|
|
506
508
|
return output === undefined ? [] : [{ name, output }];
|
|
@@ -508,11 +510,11 @@ export async function runCli(
|
|
|
508
510
|
const finishedLines = resultTargets.length === 0 && targetPresentations.length === 0
|
|
509
511
|
? [
|
|
510
512
|
...(completionReason === undefined ? [] : [`Reason ${completionReason}`]),
|
|
511
|
-
`Inspect
|
|
513
|
+
`Inspect ${commandHint(["inspect", built.id], resultScope)}`,
|
|
512
514
|
]
|
|
513
515
|
: [
|
|
514
516
|
...(completionReason === undefined ? [] : [`Reason ${completionReason}`]),
|
|
515
|
-
`Inspect
|
|
517
|
+
`Inspect ${commandHint(["inspect", built.id], resultScope)}`,
|
|
516
518
|
...resultTargets
|
|
517
519
|
.filter((item) => item.output.value.kind === "inline")
|
|
518
520
|
.slice(0, args.limit)
|
|
@@ -523,14 +525,14 @@ export async function runCli(
|
|
|
523
525
|
.filter((item) => item.output.value.kind !== "inline")
|
|
524
526
|
.slice(0, args.limit)
|
|
525
527
|
.map((item) =>
|
|
526
|
-
`Export
|
|
528
|
+
`Export ${commandHint(["get", built.id, "--output", item.name], resultScope)} --to <path>`),
|
|
527
529
|
...(resultTargets.length > 0 ? [] : targetPresentations
|
|
528
530
|
.filter((item) => item.inline !== undefined)
|
|
529
531
|
.slice(0, args.limit)
|
|
530
532
|
.map((item) => `Result ${item.published.name} = ${item.inline}`)),
|
|
531
533
|
];
|
|
532
534
|
const humanTitle = issue !== undefined
|
|
533
|
-
? "
|
|
535
|
+
? "Build needs attention"
|
|
534
536
|
: finished
|
|
535
537
|
? buildOutcome === "complete"
|
|
536
538
|
? "Build complete"
|
|
@@ -550,14 +552,14 @@ export async function runCli(
|
|
|
550
552
|
] : []),
|
|
551
553
|
...(issue === undefined ? [] : [
|
|
552
554
|
["Execution", buildOutcome ?? machine.build.work.state] as const,
|
|
553
|
-
["Result", "needs attention"] as const,
|
|
555
|
+
[issue.scope === "cleanup" ? "Cleanup" : "Result", "needs attention"] as const,
|
|
554
556
|
]),
|
|
555
557
|
], finished ? finishedLines : issue !== undefined ? [
|
|
556
|
-
`
|
|
557
|
-
`Finish
|
|
558
|
+
`Attention ${issue.scope}: ${issue.message}`,
|
|
559
|
+
`Finish ${commandHint(["result", "finish", built.id], commandScope)}`,
|
|
558
560
|
] : [
|
|
559
|
-
`Watch
|
|
560
|
-
`Cancel
|
|
561
|
+
`Watch ${commandHint(["status", built.id, "--watch"], commandScope)}`,
|
|
562
|
+
`Cancel ${commandHint(["cancel", built.id], commandScope)}`,
|
|
561
563
|
]);
|
|
562
564
|
if (buildOutcome === "failed" || issue !== undefined) io.setExitCode?.(1);
|
|
563
565
|
} finally {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { BuildResultManifest } from "@hypit/build-result";
|
|
2
2
|
|
|
3
3
|
import type { CliBuildSubmission, CliBuildView, CliRuntimeControl, CliRuntimeController } from "./runtime-port.js";
|
|
4
|
+
import { commandHint } from "./command-hint.js";
|
|
5
|
+
import type { CommandScope } from "./command-hint.js";
|
|
4
6
|
import { formatOperationProgress } from "./runtime-view.js";
|
|
5
7
|
|
|
6
8
|
const FIRST_HEARTBEAT_MS = 30_000;
|
|
@@ -122,6 +124,7 @@ export async function observeBuildView(
|
|
|
122
124
|
readonly maxWaitMs?: number;
|
|
123
125
|
readonly controller?: CliRuntimeController;
|
|
124
126
|
readonly onProgress?: (value: BuildProgressView) => void;
|
|
127
|
+
readonly commandScope?: CommandScope;
|
|
125
128
|
} = {},
|
|
126
129
|
): Promise<CliBuildView | undefined> {
|
|
127
130
|
let view: CliBuildView | undefined = initial;
|
|
@@ -158,8 +161,9 @@ export async function observeBuildView(
|
|
|
158
161
|
const worker = await options.controller.worker.status();
|
|
159
162
|
if (worker.state !== "running") {
|
|
160
163
|
throw new Error(
|
|
161
|
-
`Runtime Worker is ${worker.state}; Build ${build}
|
|
162
|
-
+ `
|
|
164
|
+
`Runtime Worker is ${worker.state}; stopped watching Build ${build}. `
|
|
165
|
+
+ `Inspect the Runtime with ${commandHint(["runtime", "status"], options.commandScope)}; `
|
|
166
|
+
+ `read execution evidence with ${commandHint(["logs", build], options.commandScope)}`,
|
|
163
167
|
);
|
|
164
168
|
}
|
|
165
169
|
}
|
|
@@ -184,6 +188,7 @@ export async function observeBuild(
|
|
|
184
188
|
readonly controller?: CliRuntimeController;
|
|
185
189
|
readonly readResult: () => Promise<BuildResultManifest | undefined>;
|
|
186
190
|
readonly onProgress?: (value: BuildProgressView) => void;
|
|
191
|
+
readonly commandScope?: CommandScope;
|
|
187
192
|
},
|
|
188
193
|
): Promise<CliBuildSubmission> {
|
|
189
194
|
const finishFromResult = async (): Promise<CliBuildSubmission> => {
|
|
@@ -3,6 +3,7 @@ import { relative, resolve } from "node:path";
|
|
|
3
3
|
import type { CanonicalValue } from "@hypit/protocol";
|
|
4
4
|
|
|
5
5
|
import type { OperationalMachineView } from "./machine-view.js";
|
|
6
|
+
import { CliUsageError } from "./usage-error.js";
|
|
6
7
|
|
|
7
8
|
export type CliTerminal = {
|
|
8
9
|
readonly isTTY: boolean;
|
|
@@ -970,6 +971,9 @@ function commandHelp(topic: string, colors: Palette): readonly string[] | undefi
|
|
|
970
971
|
" hypit auth login <endpoint-instance> [--runtime <profile>] [--slot <name>] [--from <secret-file>]",
|
|
971
972
|
" hypit auth logout <endpoint-instance> [--runtime <profile>] [--slot <name>]",
|
|
972
973
|
" All auth actions accept --workspace <project> to use that project's selection.",
|
|
974
|
+
" status shows credential presence and the Provider's declared browser login, if any.",
|
|
975
|
+
" login opens that browser flow or securely prompts for the secret; --from imports a secret instead.",
|
|
976
|
+
" Configure the service's Endpoint first. Storing a key does not install a Provider or select bindings.",
|
|
973
977
|
],
|
|
974
978
|
};
|
|
975
979
|
const selected = topics[topic];
|
|
@@ -986,6 +990,7 @@ export function writeCliHelp(io: CliIo, topic?: string): void {
|
|
|
986
990
|
io.write(`${selected.join("\n")}\n`);
|
|
987
991
|
return;
|
|
988
992
|
}
|
|
993
|
+
throw new CliUsageError(`Unknown help topic ${JSON.stringify(topic)}`, "hypit help");
|
|
989
994
|
}
|
|
990
995
|
io.write([
|
|
991
996
|
colors.accent(colors.strong("Hypit")),
|
|
@@ -1044,6 +1049,7 @@ export function renderCliError(error: unknown, options: {
|
|
|
1044
1049
|
error: {
|
|
1045
1050
|
code,
|
|
1046
1051
|
message: source.message,
|
|
1052
|
+
...(source instanceof CliUsageError ? { help: source.help } : {}),
|
|
1047
1053
|
...(options.debug && trace !== undefined && trace.length > 0 ? { trace } : {}),
|
|
1048
1054
|
},
|
|
1049
1055
|
}, null, 2)}\n`;
|
|
@@ -1058,6 +1064,8 @@ export function renderCliError(error: unknown, options: {
|
|
|
1058
1064
|
];
|
|
1059
1065
|
if (options.debug && trace !== undefined && trace.length > 0) {
|
|
1060
1066
|
lines.push("", colors.dim(trace));
|
|
1067
|
+
} else if (source instanceof CliUsageError) {
|
|
1068
|
+
lines.push("", `Usage ${source.help}`);
|
|
1061
1069
|
} else {
|
|
1062
1070
|
lines.push("", colors.dim("Run with --debug to include the internal stack trace."));
|
|
1063
1071
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Argument errors point to public usage rather than an internal stack trace. */
|
|
2
|
+
export class CliUsageError extends Error {
|
|
3
|
+
readonly code = "CLI_USAGE";
|
|
4
|
+
constructor(message: string, readonly help: string, options?: ErrorOptions) {
|
|
5
|
+
super(message, options);
|
|
6
|
+
this.name = "CliUsageError";
|
|
7
|
+
}
|
|
8
|
+
}
|
package/packages/cli/src/view.ts
CHANGED
|
@@ -8,6 +8,8 @@ import type {
|
|
|
8
8
|
import { buildIdCreatedAt } from "@hypit/protocol";
|
|
9
9
|
import type { TypeRef } from "@hypit/protocol";
|
|
10
10
|
import type { BuildView } from "@hypit/runtime-host-node";
|
|
11
|
+
import { commandHint } from "./command-hint.js";
|
|
12
|
+
import type { CommandScope } from "./command-hint.js";
|
|
11
13
|
|
|
12
14
|
export type PublicOutputKind = "scalar" | "resource" | "composite";
|
|
13
15
|
|
|
@@ -159,6 +161,7 @@ export function buildStatusView(options: {
|
|
|
159
161
|
readonly result?: BuildResultManifest;
|
|
160
162
|
readonly resultReadError?: string;
|
|
161
163
|
readonly verbose?: boolean;
|
|
164
|
+
readonly commandScope?: CommandScope;
|
|
162
165
|
}): CliBuildStatusView {
|
|
163
166
|
const resultState = options.resultReadError !== undefined
|
|
164
167
|
? "unavailable" as const
|
|
@@ -195,7 +198,7 @@ export function buildStatusView(options: {
|
|
|
195
198
|
attention: issue !== undefined
|
|
196
199
|
? {
|
|
197
200
|
message: issue.message,
|
|
198
|
-
|
|
201
|
+
action: commandHint(["result", "finish", options.id], options.commandScope),
|
|
199
202
|
}
|
|
200
203
|
: { message: options.resultReadError! },
|
|
201
204
|
}),
|
|
@@ -17,6 +17,11 @@ Build. Credentials are resolved only for slots declared by the selected endpoint
|
|
|
17
17
|
of the same credential are coalesced. Cancellation is best effort and never rolls back completed work.
|
|
18
18
|
A failed action retains its receipt and error for the Result; the Driver does not retry or reconcile it.
|
|
19
19
|
|
|
20
|
+
Immediate calls and asynchronous submit, poll and collect actions receive the same progress and
|
|
21
|
+
diagnostic callbacks. Progress reaches the caller while the action is running; changes of phase also
|
|
22
|
+
enter the execution log. The Endpoint supplies the content, and the Driver forwards it with the
|
|
23
|
+
selected Endpoint identity without interpreting service-specific phases or treating progress as a receipt.
|
|
24
|
+
|
|
20
25
|
`acceptOperation()` validates an already received value without making a remote call. Runtime can
|
|
21
26
|
retain such a sibling result when another Need fails, without polling unfinished jobs to completion.
|
|
22
27
|
The Driver validates returned values before offering a command result to Core. It does not load
|
|
@@ -22,6 +22,7 @@ import type {
|
|
|
22
22
|
CredentialStore,
|
|
23
23
|
CredentialValue,
|
|
24
24
|
OperationSnapshot,
|
|
25
|
+
OperationProgress,
|
|
25
26
|
OperationStore,
|
|
26
27
|
RuntimeExecutionContext,
|
|
27
28
|
RuntimeExecutionResult,
|
|
@@ -349,6 +350,23 @@ export class NodeDriver {
|
|
|
349
350
|
return result;
|
|
350
351
|
}
|
|
351
352
|
|
|
353
|
+
#endpointObservers(endpoint: string, context?: RuntimeExecutionContext) {
|
|
354
|
+
let phase: string | undefined;
|
|
355
|
+
return {
|
|
356
|
+
reportProgress: async (progress: OperationProgress) => {
|
|
357
|
+
await context?.reportProgress?.({ endpoint, progress });
|
|
358
|
+
if (progress.phase !== phase) {
|
|
359
|
+
phase = progress.phase;
|
|
360
|
+
await context?.recordExecution?.({ endpoint, kind: "phase", phase });
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
...(context?.recordExecution === undefined ? {} : {
|
|
364
|
+
reportDiagnostic: (diagnostic: import("@hypit/runtime").ExecutionDiagnostic) =>
|
|
365
|
+
context.recordExecution!({ endpoint, kind: "diagnostic", ...diagnostic }),
|
|
366
|
+
}),
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
352
370
|
async #advanceOperationStep(
|
|
353
371
|
operation: OperationSnapshot,
|
|
354
372
|
registration: EndpointRegistration,
|
|
@@ -374,10 +392,7 @@ export class NodeDriver {
|
|
|
374
392
|
command: structuredClone(command), need: structuredClone(command.need),
|
|
375
393
|
resources: this.#resourceStore(operation.build), operation: operation.id,
|
|
376
394
|
credentials: await this.#endpointCredentials({ ...registration, credentials: operation.credentials ?? registration.credentials ?? {} }),
|
|
377
|
-
...(
|
|
378
|
-
reportDiagnostic: (diagnostic: import("@hypit/runtime").ExecutionDiagnostic) =>
|
|
379
|
-
runtimeContext.recordExecution!({ endpoint: operation.endpoint, kind: "diagnostic", ...diagnostic }),
|
|
380
|
-
}),
|
|
395
|
+
...this.#endpointObservers(operation.endpoint, runtimeContext),
|
|
381
396
|
checkpoint: async (checkpoint: import("@hypit/endpoint-kit").EndpointCheckpoint) => {
|
|
382
397
|
await operations.update(operation.id, { status: "pending", ...checkpoint,
|
|
383
398
|
submission: "accepted", acknowledgedAt: operation.acknowledgedAt ?? Date.now(), wakeAt: Date.now(), progress: { phase: checkpoint.remoteEnded ? "collecting" : "submitted" } });
|
|
@@ -493,7 +508,6 @@ export class NodeDriver {
|
|
|
493
508
|
);
|
|
494
509
|
}
|
|
495
510
|
}
|
|
496
|
-
let phase: string | undefined;
|
|
497
511
|
await context?.recordExecution?.({ endpoint: executable.endpointId, kind: "started" });
|
|
498
512
|
try {
|
|
499
513
|
const result = await executable.registration.handler({
|
|
@@ -501,16 +515,7 @@ export class NodeDriver {
|
|
|
501
515
|
need: structuredClone(executable.command.need),
|
|
502
516
|
resources: this.#resourceStore(context?.build),
|
|
503
517
|
credentials: await this.#endpointCredentials(executable.registration),
|
|
504
|
-
|
|
505
|
-
await context?.reportProgress?.({ endpoint: executable.endpointId, progress });
|
|
506
|
-
if (progress.phase !== phase) {
|
|
507
|
-
phase = progress.phase;
|
|
508
|
-
await context?.recordExecution?.({ endpoint: executable.endpointId, kind: "phase", phase });
|
|
509
|
-
}
|
|
510
|
-
},
|
|
511
|
-
...(context?.recordExecution === undefined ? {} : {
|
|
512
|
-
reportDiagnostic: (diagnostic) => context.recordExecution!({ endpoint: executable.endpointId, kind: "diagnostic", ...diagnostic }),
|
|
513
|
-
}),
|
|
518
|
+
...this.#endpointObservers(executable.endpointId, context),
|
|
514
519
|
});
|
|
515
520
|
const event = await this.#endpointEvent(state, executable, result);
|
|
516
521
|
await context?.recordExecution?.({ endpoint: executable.endpointId, kind: "completed" });
|
|
@@ -35,12 +35,21 @@ without changing Core demand. Each resource declares a `limit` and optional `uni
|
|
|
35
35
|
A capability may add `resources` and a pure `unitsForRequest(request)` resolver for quantities of
|
|
36
36
|
already declared resources. Runtime admits all claims atomically for one `fulfill-need` Command.
|
|
37
37
|
|
|
38
|
-
A
|
|
38
|
+
A running immediate call or asynchronous action can report its current activity with
|
|
39
39
|
`await context.reportProgress?.({ phase: "processing", completed: 12, total: 40, unit: "items" })`.
|
|
40
40
|
The Provider chooses meaningful phases and quantities and reports non-secret, human-readable facts.
|
|
41
41
|
The Runtime attaches them to the currently executing Command; they do not change its outcome,
|
|
42
42
|
scheduling or Core facts. Completion clears the live activity. Direct callers may omit the callback.
|
|
43
|
-
For asynchronous work,
|
|
43
|
+
For asynchronous work, these callbacks describe work inside `start`, `poll` or `collect`, such as
|
|
44
|
+
preparing references or downloading results. A returned `pending.progress` describes the acknowledged
|
|
45
|
+
remote task between actions. Neither form of progress substitutes for a received task ID or receipt.
|
|
46
|
+
|
|
47
|
+
Separate facts available from the request from actions needed to fulfill it. Check known input
|
|
48
|
+
limits and determine the requested service operation before transferring its resources. If the
|
|
49
|
+
service exposes account-specific capability information, use that evidence for the selected request;
|
|
50
|
+
an API without such a query needs no invented discovery step. A Provider owns the meaning of its
|
|
51
|
+
public error codes and reasons. Preserve the failed operation and that evidence, distinguishing what
|
|
52
|
+
was never submitted from a submission whose remote outcome is unknown.
|
|
44
53
|
|
|
45
54
|
Asynchronous execution moves forward through `start`, `poll`, and optional `collect`. `start` returns
|
|
46
55
|
a task handle; `pending` means an acknowledged task is still running. `ready` records remote completion
|
|
@@ -101,7 +101,7 @@ export type EndpointInvocationContext = {
|
|
|
101
101
|
readonly credentials: Readonly<Record<string, EndpointCredential>>;
|
|
102
102
|
/** Explicit non-secret diagnostic output. The Provider owns its content, never its storage. */
|
|
103
103
|
readonly reportDiagnostic?: (diagnostic: import("@hypit/runtime").ExecutionDiagnostic) => Promise<void>;
|
|
104
|
-
/** Report non-secret activity
|
|
104
|
+
/** Report non-secret activity while an immediate call or asynchronous action is still running. */
|
|
105
105
|
readonly reportProgress?: (progress: OperationProgress) => Promise<void>;
|
|
106
106
|
};
|
|
107
107
|
|
|
@@ -9,6 +9,16 @@ implementations. `sealGenerationPortTable` describes a model's inputs; `Generati
|
|
|
9
9
|
`selectWireModelForRequest` applies the same route selection without resolving media bytes. During
|
|
10
10
|
planning, a Provider may add the model-port names already attached as future graph inputs; the
|
|
11
11
|
selector does not inspect graph structure or interpret media roles.
|
|
12
|
+
Route selection here applies declared input-mode mappings for the already chosen exact capability;
|
|
13
|
+
it does not search for an alternative model, service or account.
|
|
14
|
+
|
|
15
|
+
`compileWireRequest` awaits its media URL resolver, so compilation can have external effects when
|
|
16
|
+
that resolver uploads files. Use `selectWireModelForRequest` for request identity and known-port
|
|
17
|
+
checks before those effects; pricing and execution can share the same mapping. A Provider can also
|
|
18
|
+
describe its API operation from the authored ports. Service-specific support queries belong to that
|
|
19
|
+
Provider and only use operations its API actually exposes. The generic helper neither queries a
|
|
20
|
+
catalogue nor switches to another route after a failure. Actual URL resolution belongs to request
|
|
21
|
+
execution, not to discovering a model name or making a planning placeholder.
|
|
12
22
|
|
|
13
23
|
The package owns `GenerationRequest`, `GeneratedImageSet` and `GeneratedVideoSet` identities,
|
|
14
24
|
schemas, validators and graph facets. Generated sets are atomic Products: a Provider persists the
|
|
@@ -16,7 +16,7 @@ admits them into the current Build's working byte area. Image references use Hyp
|
|
|
16
16
|
`reference_image_urls`, `reference_videos`, and `reference_audios` fields. A single reference video
|
|
17
17
|
remains in `reference_videos`; `ref_video_url` is reserved for a model's source-video port. First/last-frame images use `first_frame` and `last_frame`.
|
|
18
18
|
|
|
19
|
-
Seedance 2.5 (`@hypit/seedance` model `2.5`) maps to `
|
|
19
|
+
Seedance 2.5 (`@hypit/seedance` model `2.5`) maps to `seedance-2.5` and supports
|
|
20
20
|
`480p`, `720p` and `1080p`. The Provider passes the authored `resolution` to `POST /v1/videos`;
|
|
21
21
|
omitting it in the Seedance Surface defaults to `720p`.
|
|
22
22
|
|
|
@@ -31,11 +31,44 @@ The current HypiHub GPT Image 2 route has these service-specific limits:
|
|
|
31
31
|
HypiHub owns this support check independently: it leaves the GPT Image model package unchanged. When the service surface changes, this Provider can change without changing
|
|
32
32
|
the model or another Provider.
|
|
33
33
|
|
|
34
|
-
Model identity
|
|
35
|
-
|
|
34
|
+
Model identity and input mode are separate. The mapping uses HypiHub's canonical model names:
|
|
35
|
+
`gpt-image-2`, `seedream-5-lite`, `minimax-h3`, `grok-imagine-video` and the individual Seedance names.
|
|
36
|
+
An image request without references uses `/images/generations`; image edits use `/images/edits`
|
|
37
|
+
with the same model name. Video requests use `/videos`, preserving reference images, reference
|
|
38
|
+
videos and first/last frames in their distinct fields. Old operation-specific names are not needed
|
|
39
|
+
to express these modes; compatibility with previously released clients belongs to the service.
|
|
40
|
+
|
|
41
|
+
Seedream 5 Lite remains Lite across input modes, and Grok 1.5 Preview remains Preview.
|
|
42
|
+
A deployment's current catalogue may offer
|
|
36
43
|
newer models or omit one implemented here. Availability and unsupported-input errors retain their
|
|
37
44
|
service explanation; they do not imply expired credentials or authorize substituting another model.
|
|
38
45
|
|
|
46
|
+
Before resolving or uploading references, the Provider prepares the exact model and operation from
|
|
47
|
+
the authored ports and its mapping, then queries that model's authenticated directory entry. Image
|
|
48
|
+
editing is determined from the mapped media inputs, without manufacturing placeholder URLs or
|
|
49
|
+
uploading to discover the request mode. The same preparation serves images, videos and speech.
|
|
50
|
+
The request is then translated with real reference URLs and submitted to the selected operation.
|
|
51
|
+
These are internal Provider functions; Author Sources, CLI commands and Runtime scheduling are unchanged.
|
|
52
|
+
|
|
53
|
+
Progress identifies the directory query, request preparation and submission. A directory failure
|
|
54
|
+
retains the model, operation and service evidence, and states that this invocation uploaded no
|
|
55
|
+
references and submitted no generation. A missing or malformed operation list leaves support unknown;
|
|
56
|
+
an explicit list without the requested operation reports the actual list. No alternative model,
|
|
57
|
+
operation or account is attempted. Directory support alone does not establish balance, every input
|
|
58
|
+
combination or eventual generation success. Preparation failure also reports that generation was not
|
|
59
|
+
submitted; an interrupted submission retains its actual evidence without claiming no remote work exists.
|
|
60
|
+
|
|
61
|
+
The Provider interprets HypiHub's [HTTP errors](https://hypit.ai/api-reference/errors/) and
|
|
62
|
+
[job errors](https://hypit.ai/api-reference/jobs/) locally. Failures retain the service code,
|
|
63
|
+
HTTP method/route/status, requested model and `X-Request-Id` when available, plus the public reason.
|
|
64
|
+
`Retry-After` remains evidence and does not start another generation attempt. Job failures retain
|
|
65
|
+
`error_code`, `error` and their receipt even when the create response is already terminal.
|
|
66
|
+
Known error messages are not cut to a fixed prefix; only an unstructured non-JSON response uses
|
|
67
|
+
a marked excerpt. Unrelated response fields and signed asset URLs are not diagnostic content.
|
|
68
|
+
Runtime and Result retain ordinary failure codes/messages without interpreting HypiHub fields.
|
|
69
|
+
Immediate Endpoint exceptions keep the same evidence in their message. A `401` alone does not
|
|
70
|
+
choose OAuth over API-key configuration or establish that another login will fix the account.
|
|
71
|
+
|
|
39
72
|
For moving portraits, [Volcengine Matting](../volcengine-matting/README.md) maps
|
|
40
73
|
`@hypit/volcengine-matting@1#matte-portrait-video` to `POST /v1/videos` with
|
|
41
74
|
`model: "matte-portrait-video"`, `ref_video_url` and `format` (`WEBM` by default, or `MOV`).
|
|
@@ -122,8 +155,10 @@ catalog to verify configured capabilities; ordinary preflight never makes that r
|
|
|
122
155
|
declares HypiHub's public pricing page, `https://hypit.ai/commercial/pricing/`, as its price source.
|
|
123
156
|
For each selected Need, `readPricing` resolves the corresponding HypiHub model and returns the service's
|
|
124
157
|
authenticated `GET /v1/pricing?model=<model>` response unchanged together with that URL. It covers
|
|
125
|
-
generation, alignment, Voice Design and Voice Clone through the same mechanism
|
|
126
|
-
|
|
158
|
+
generation, alignment, Voice Design and Voice Clone through the same mechanism. The document's
|
|
159
|
+
per-operation prices are retained alongside its default price, including when references are still
|
|
160
|
+
pending. A model's default price is not a quote for every input mode. The Provider does not maintain
|
|
161
|
+
a second list of billing formulas or calculate a request total.
|
|
127
162
|
|
|
128
163
|
The Provider declares its implemented speech capabilities alongside image, video and alignment.
|
|
129
164
|
Voice Design produces an accepted voice-reference Resource, and Voice Clone uses that
|
|
@@ -148,7 +183,7 @@ Execution policy remains local to this Provider:
|
|
|
148
183
|
| `requestTimeoutMs` | 300 seconds | ordinary Provider HTTP requests |
|
|
149
184
|
| `oauthRequestTimeoutMs` | 30 seconds | OAuth token exchange and refresh |
|
|
150
185
|
| `pricingRequestTimeoutMs` | 30 seconds | authenticated pricing requests |
|
|
151
|
-
| `operationTimeoutMs` | 20 minutes | one
|
|
186
|
+
| `operationTimeoutMs` | 20 minutes | how long this Provider observes one asynchronous operation; expiry does not cancel the remote job |
|
|
152
187
|
| `uploadConcurrency` | 8 | whole file sessions per origin/credential within this process |
|
|
153
188
|
| `uploadPartTimeoutMs` | 5 minutes | one upload part |
|
|
154
189
|
| `uploadPartAttempts` | 3 | attempts for one upload part |
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** HypiHub's public error envelope, kept at the service boundary. */
|
|
2
|
+
function record(value: unknown): Record<string, unknown> | undefined {
|
|
3
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
4
|
+
? value as Record<string, unknown> : undefined;
|
|
5
|
+
}
|
|
6
|
+
function text(value: unknown): string | undefined {
|
|
7
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Responses may mention a signed asset URL. Keep the reason, not its access capability.
|
|
11
|
+
export function safeHypiHubReason(value: string): string {
|
|
12
|
+
return value.replace(/https?:\/\/\S+/giu, "[redacted-url]");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class HypiHubServiceError extends Error {
|
|
16
|
+
constructor(readonly code: string, message: string) { super(message); }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class HypiHubHttpError extends HypiHubServiceError {
|
|
20
|
+
readonly retryAfterMs?: number;
|
|
21
|
+
constructor(readonly status: number, response: { readonly headers: Headers }, bodyText: string,
|
|
22
|
+
request: { readonly method: string; readonly url: string; readonly model?: string }) {
|
|
23
|
+
let body: Record<string, unknown> | undefined;
|
|
24
|
+
try { body = record(JSON.parse(bodyText)); } catch { /* Non-JSON gateway failures still have HTTP evidence. */ }
|
|
25
|
+
const error = record(body?.error);
|
|
26
|
+
const flatError = text(body?.error);
|
|
27
|
+
const code = text(error?.code)
|
|
28
|
+
?? (flatError !== undefined && /^[a-z][a-z0-9_]*$/iu.test(flatError) ? flatError : "HYPIHUB_HTTP_ERROR");
|
|
29
|
+
const reason = text(error?.message) ?? text(body?.error_description)
|
|
30
|
+
?? (flatError !== code ? flatError : undefined)
|
|
31
|
+
?? (body === undefined ? text(bodyText.slice(0, 2000)) : undefined);
|
|
32
|
+
const url = new URL(request.url);
|
|
33
|
+
const model = request.model ?? url.searchParams.get("model")
|
|
34
|
+
?? (url.pathname.includes("/models/") ? decodeURIComponent(url.pathname.split("/models/")[1]!) : undefined);
|
|
35
|
+
const requestId = text(response.headers.get("x-request-id"));
|
|
36
|
+
const retryAfter = text(response.headers.get("retry-after"));
|
|
37
|
+
const facts = [
|
|
38
|
+
`HypiHub HTTP ${status}`, code, `${request.method} ${url.origin}${url.pathname}`,
|
|
39
|
+
...(model == null ? [] : [`model=${model}`]),
|
|
40
|
+
...(requestId === undefined ? [] : [`request=${requestId}`]),
|
|
41
|
+
...(retryAfter === undefined ? [] : [`retry-after=${retryAfter}`]),
|
|
42
|
+
];
|
|
43
|
+
super(code, `${facts.join("; ")}${reason === undefined ? "" : `: ${safeHypiHubReason(reason)}`}`
|
|
44
|
+
+ (body === undefined && bodyText.length > 2000 ? " [response excerpt truncated]" : ""));
|
|
45
|
+
const delay = retryAfter === undefined ? NaN : /^\d+$/u.test(retryAfter)
|
|
46
|
+
? Number(retryAfter) * 1000 : Date.parse(retryAfter) - Date.now();
|
|
47
|
+
if (Number.isFinite(delay)) this.retryAfterMs = Math.max(0, delay);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function hypiHubJobFailure(job: Record<string, unknown>, id: string): HypiHubServiceError | undefined {
|
|
52
|
+
const status = job.status;
|
|
53
|
+
if (!["failed", "queue_expired", "canceled", "cancelled"].includes(String(status))) return undefined;
|
|
54
|
+
const error = record(job.error);
|
|
55
|
+
const code = text(job.error_code) ?? text(error?.code) ?? "HYPIHUB_JOB_FAILED";
|
|
56
|
+
const reason = text(job.error) ?? text(error?.message) ?? text(job.message) ?? text(job.reason) ?? text(job.detail);
|
|
57
|
+
const model = text(job.model);
|
|
58
|
+
return new HypiHubServiceError(code,
|
|
59
|
+
`HypiHub job ${id} ${status}; ${code}${model === undefined ? "" : `; model=${model}`}`
|
|
60
|
+
+ (reason === undefined ? "" : `: ${safeHypiHubReason(reason)}`));
|
|
61
|
+
}
|
|
@@ -12,8 +12,8 @@ const MIMO_SPEECH: ModuleRef = { name: "@hypit/mimo-speech", version: "1" };
|
|
|
12
12
|
const FISHAUDIO_SPEECH: ModuleRef = { name: "@hypit/fishaudio-speech", version: "1" };
|
|
13
13
|
const ELEVENLABS_SPEECH: ModuleRef = { name: "@hypit/elevenlabs-speech", version: "1" };
|
|
14
14
|
|
|
15
|
-
const seedance = (name: string
|
|
16
|
-
capability: { module: SEEDANCE, name }, result: "video", routes: [{ model }],
|
|
15
|
+
const seedance = (name: string): GenerationWireMapping => ({
|
|
16
|
+
capability: { module: SEEDANCE, name }, result: "video", routes: [{ model: name }],
|
|
17
17
|
fields: {
|
|
18
18
|
prompt: { as: "value", field: "prompt" },
|
|
19
19
|
referenceImage: { as: "urlArray", field: "reference_image_urls", resourceFields: ["personReference"] },
|
|
@@ -38,15 +38,12 @@ export const hypiHubMappings: readonly GenerationWireMapping[] = [
|
|
|
38
38
|
format: { as: "value", field: "format", whenAbsent: "WEBM" },
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
|
-
seedance("seedance-2"
|
|
42
|
-
seedance("seedance-2-fast"
|
|
43
|
-
seedance("seedance-2-mini"
|
|
44
|
-
seedance("seedance-2.5"
|
|
41
|
+
seedance("seedance-2"),
|
|
42
|
+
seedance("seedance-2-fast"),
|
|
43
|
+
seedance("seedance-2-mini"),
|
|
44
|
+
seedance("seedance-2.5"),
|
|
45
45
|
{
|
|
46
|
-
capability: { module: GPT_IMAGE, name: "gpt-image-2" }, result: "image", routes: [
|
|
47
|
-
{ model: "gpt-image-2-image-to-image", whenPresent: ["images"] },
|
|
48
|
-
{ model: "gpt-image-2-text-to-image" },
|
|
49
|
-
],
|
|
46
|
+
capability: { module: GPT_IMAGE, name: "gpt-image-2" }, result: "image", routes: [{ model: "gpt-image-2" }],
|
|
50
47
|
fields: {
|
|
51
48
|
prompt: { as: "value", field: "prompt" },
|
|
52
49
|
aspectRatio: { as: "value", field: "aspect_ratio" },
|
|
@@ -66,10 +63,7 @@ export const hypiHubMappings: readonly GenerationWireMapping[] = [
|
|
|
66
63
|
},
|
|
67
64
|
})),
|
|
68
65
|
{
|
|
69
|
-
capability: { module: SEEDREAM, name: "seedream-5-lite" }, result: "image", routes: [
|
|
70
|
-
{ model: "seedream/5-lite-image-to-image", whenPresent: ["images"] },
|
|
71
|
-
{ model: "seedream/5-lite-text-to-image" },
|
|
72
|
-
],
|
|
66
|
+
capability: { module: SEEDREAM, name: "seedream-5-lite" }, result: "image", routes: [{ model: "seedream-5-lite" }],
|
|
73
67
|
fields: {
|
|
74
68
|
prompt: { as: "value", field: "prompt" },
|
|
75
69
|
aspectRatio: { as: "value", field: "aspect_ratio" },
|
|
@@ -80,13 +74,7 @@ export const hypiHubMappings: readonly GenerationWireMapping[] = [
|
|
|
80
74
|
},
|
|
81
75
|
},
|
|
82
76
|
{
|
|
83
|
-
capability: { module: MINIMAX, name: "minimax-h3" }, result: "video", routes: [
|
|
84
|
-
{ model: "minimax-h3/image-to-video", whenPresent: ["lastFrame"] },
|
|
85
|
-
{ model: "minimax-h3/image-to-video", whenPresent: ["firstFrame"] },
|
|
86
|
-
{ model: "minimax-h3/reference-to-video", whenPresent: ["referenceImage"] },
|
|
87
|
-
{ model: "minimax-h3/reference-to-video", whenPresent: ["referenceVideo"] },
|
|
88
|
-
{ model: "minimax-h3/text-to-video" },
|
|
89
|
-
],
|
|
77
|
+
capability: { module: MINIMAX, name: "minimax-h3" }, result: "video", routes: [{ model: "minimax-h3" }],
|
|
90
78
|
fields: {
|
|
91
79
|
prompt: { as: "value", field: "prompt" }, duration: { as: "value", field: "seconds" },
|
|
92
80
|
resolution: { as: "value", field: "resolution", whenAbsent: "2k" }, aspectRatio: { as: "value", field: "aspect_ratio" },
|
|
@@ -98,10 +86,7 @@ export const hypiHubMappings: readonly GenerationWireMapping[] = [
|
|
|
98
86
|
},
|
|
99
87
|
},
|
|
100
88
|
{
|
|
101
|
-
capability: { module: GROK, name: "grok-imagine-video" }, result: "video", routes: [
|
|
102
|
-
{ model: "grok-imagine/image-to-video", whenPresent: ["images"] },
|
|
103
|
-
{ model: "grok-imagine/text-to-video" },
|
|
104
|
-
],
|
|
89
|
+
capability: { module: GROK, name: "grok-imagine-video" }, result: "video", routes: [{ model: "grok-imagine-video" }],
|
|
105
90
|
fields: {
|
|
106
91
|
prompt: { as: "value", field: "prompt" }, duration: { as: "value", field: "seconds" },
|
|
107
92
|
resolution: { as: "value", field: "resolution" }, aspectRatio: { as: "value", field: "aspect_ratio" },
|