@teith/openclaw-runware-provider 0.2.5 → 0.2.7
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/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -89
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +107 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +123 -0
- package/dist/models.js.map +1 -0
- package/dist/openclaw-api.d.ts +18 -39
- package/dist/openclaw-api.d.ts.map +1 -1
- package/dist/openclaw-api.js +5 -3
- package/dist/openclaw-api.js.map +1 -1
- package/dist/provider-discovery.d.ts +25 -28
- package/dist/provider-discovery.d.ts.map +1 -1
- package/dist/provider-discovery.js +21 -67
- package/dist/provider-discovery.js.map +1 -1
- package/dist/types.d.ts +1 -6
- package/dist/types.d.ts.map +1 -1
- package/openclaw.plugin.json +10 -11
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
import type { PluginEntry } from "./openclaw-api.js";
|
|
2
|
+
/**
|
|
3
|
+
* Plugin entry that openclaw's plugin loader invokes after `npm install`-ing
|
|
4
|
+
* this package into `~/.openclaw/extensions/`. The loader calls `register()`
|
|
5
|
+
* once with the runtime API; we declare three surfaces on it:
|
|
6
|
+
*
|
|
7
|
+
* 1. `registerProvider({ catalog: { run } })`
|
|
8
|
+
* Fallback inference-catalog surface. Future openclaw versions are
|
|
9
|
+
* expected to consult this for both the model list and the OpenAI-
|
|
10
|
+
* compatible inference client; current 2026.5.x does not call it for
|
|
11
|
+
* external plugins, but declaring it costs nothing.
|
|
12
|
+
*
|
|
13
|
+
* 2. `registerModelCatalogProvider({ kinds, liveCatalog })`
|
|
14
|
+
* UI picker surface ("forward path" per the architecture docs). Not
|
|
15
|
+
* called by 2026.5.x for external plugins either — the actively used
|
|
16
|
+
* surface today is provider-discovery.ts loaded via the manifest's
|
|
17
|
+
* `providerCatalogEntry` field.
|
|
18
|
+
*
|
|
19
|
+
* The provider-discovery file is the one openclaw 2026.5.x actually calls
|
|
20
|
+
* for catalog resolution. All three surfaces share the same model-building
|
|
21
|
+
* code in models.ts, so they stay consistent automatically.
|
|
22
|
+
*/
|
|
2
23
|
declare const entry: PluginEntry;
|
|
3
24
|
export default entry;
|
|
4
25
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,QAAA,MAAM,KAAK,EAAE,WAkCZ,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,77 +1,31 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { API_KEY_ENV_VAR, BASE_URL_ENV_VAR, PROVIDER_ID, PROVIDER_LABEL, buildCatalogRows, buildProvider, resolveApiKey, resolveBaseUrl, } from "./models.js";
|
|
2
2
|
const PLUGIN_ID = "runware-openclaw-provider";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
function humanizeModelId(id) {
|
|
26
|
-
return id
|
|
27
|
-
.replace(/[-_:@]/g, " ")
|
|
28
|
-
.replace(/\bfp8\b/gi, "FP8")
|
|
29
|
-
.trim()
|
|
30
|
-
.split(/\s+/)
|
|
31
|
-
.map((w) => (w.length > 0 ? w[0].toUpperCase() + w.slice(1) : w))
|
|
32
|
-
.join(" ");
|
|
33
|
-
}
|
|
34
|
-
async function buildProvider(apiKey, baseUrl) {
|
|
35
|
-
const ids = await fetchModelIds(baseUrl, apiKey);
|
|
36
|
-
return {
|
|
37
|
-
baseUrl,
|
|
38
|
-
apiKey,
|
|
39
|
-
api: "openai-completions",
|
|
40
|
-
timeoutSeconds: REQUEST_TIMEOUT_SECONDS,
|
|
41
|
-
models: ids.map((id) => ({
|
|
42
|
-
id,
|
|
43
|
-
name: humanizeModelId(id),
|
|
44
|
-
reasoning: true,
|
|
45
|
-
input: ["text"],
|
|
46
|
-
contextWindow: MODEL_CONTEXT_WINDOW,
|
|
47
|
-
maxTokens: MODEL_MAX_TOKENS,
|
|
48
|
-
cost: ZERO_COST,
|
|
49
|
-
params: MODEL_PARAMS,
|
|
50
|
-
})),
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
async function buildCatalogRows(apiKey, baseUrl) {
|
|
54
|
-
const ids = await fetchModelIds(baseUrl, apiKey);
|
|
55
|
-
return ids.map((id) => ({
|
|
56
|
-
kind: "text",
|
|
57
|
-
provider: PROVIDER_ID,
|
|
58
|
-
model: id,
|
|
59
|
-
label: humanizeModelId(id),
|
|
60
|
-
source: "live",
|
|
61
|
-
reasoning: true,
|
|
62
|
-
input: ["text"],
|
|
63
|
-
contextWindow: MODEL_CONTEXT_WINDOW,
|
|
64
|
-
maxTokens: MODEL_MAX_TOKENS,
|
|
65
|
-
cost: ZERO_COST,
|
|
66
|
-
}));
|
|
67
|
-
}
|
|
3
|
+
/**
|
|
4
|
+
* Plugin entry that openclaw's plugin loader invokes after `npm install`-ing
|
|
5
|
+
* this package into `~/.openclaw/extensions/`. The loader calls `register()`
|
|
6
|
+
* once with the runtime API; we declare three surfaces on it:
|
|
7
|
+
*
|
|
8
|
+
* 1. `registerProvider({ catalog: { run } })`
|
|
9
|
+
* Fallback inference-catalog surface. Future openclaw versions are
|
|
10
|
+
* expected to consult this for both the model list and the OpenAI-
|
|
11
|
+
* compatible inference client; current 2026.5.x does not call it for
|
|
12
|
+
* external plugins, but declaring it costs nothing.
|
|
13
|
+
*
|
|
14
|
+
* 2. `registerModelCatalogProvider({ kinds, liveCatalog })`
|
|
15
|
+
* UI picker surface ("forward path" per the architecture docs). Not
|
|
16
|
+
* called by 2026.5.x for external plugins either — the actively used
|
|
17
|
+
* surface today is provider-discovery.ts loaded via the manifest's
|
|
18
|
+
* `providerCatalogEntry` field.
|
|
19
|
+
*
|
|
20
|
+
* The provider-discovery file is the one openclaw 2026.5.x actually calls
|
|
21
|
+
* for catalog resolution. All three surfaces share the same model-building
|
|
22
|
+
* code in models.ts, so they stay consistent automatically.
|
|
23
|
+
*/
|
|
68
24
|
const entry = {
|
|
69
25
|
id: PLUGIN_ID,
|
|
70
26
|
name: PROVIDER_LABEL,
|
|
71
27
|
description: "Runware — unified OpenAI-compatible access to Claude, GPT, Gemini, Qwen, GLM, MiniMax, Kimi, and Gemma.",
|
|
72
28
|
register(api) {
|
|
73
|
-
// eslint-disable-next-line no-console
|
|
74
|
-
console.error("[runware-plugin] register called, api keys:", Object.keys(api ?? {}));
|
|
75
29
|
api.registerProvider({
|
|
76
30
|
id: PROVIDER_ID,
|
|
77
31
|
label: PROVIDER_LABEL,
|
|
@@ -81,43 +35,24 @@ const entry = {
|
|
|
81
35
|
catalog: {
|
|
82
36
|
order: "simple",
|
|
83
37
|
run: async (ctx) => {
|
|
84
|
-
// eslint-disable-next-line no-console
|
|
85
|
-
console.error("[runware-plugin] catalog.run called, ctx keys:", Object.keys(ctx ?? {}));
|
|
86
38
|
const apiKey = resolveApiKey(ctx);
|
|
87
|
-
// eslint-disable-next-line no-console
|
|
88
|
-
console.error("[runware-plugin] catalog.run apiKey:", apiKey ? "yes" : "no");
|
|
89
39
|
if (!apiKey)
|
|
90
40
|
return null;
|
|
91
|
-
const
|
|
92
|
-
const provider = await buildProvider(apiKey, baseUrl);
|
|
93
|
-
// eslint-disable-next-line no-console
|
|
94
|
-
console.error("[runware-plugin] catalog.run returning provider with", provider.models.length, "models");
|
|
41
|
+
const provider = await buildProvider(apiKey, resolveBaseUrl(ctx.env));
|
|
95
42
|
return { provider };
|
|
96
43
|
},
|
|
97
44
|
},
|
|
98
45
|
});
|
|
99
|
-
// eslint-disable-next-line no-console
|
|
100
|
-
console.error("[runware-plugin] registerProvider DONE");
|
|
101
46
|
api.registerModelCatalogProvider({
|
|
102
47
|
provider: PROVIDER_ID,
|
|
103
48
|
kinds: ["text"],
|
|
104
49
|
liveCatalog: async (ctx) => {
|
|
105
|
-
// eslint-disable-next-line no-console
|
|
106
|
-
console.error("[runware-plugin] liveCatalog called, ctx keys:", Object.keys(ctx ?? {}));
|
|
107
50
|
const apiKey = resolveApiKey(ctx);
|
|
108
|
-
// eslint-disable-next-line no-console
|
|
109
|
-
console.error("[runware-plugin] liveCatalog apiKey:", apiKey ? "yes" : "no");
|
|
110
51
|
if (!apiKey)
|
|
111
52
|
return null;
|
|
112
|
-
|
|
113
|
-
const rows = await buildCatalogRows(apiKey, baseUrl);
|
|
114
|
-
// eslint-disable-next-line no-console
|
|
115
|
-
console.error("[runware-plugin] liveCatalog returning", rows.length, "rows");
|
|
116
|
-
return rows;
|
|
53
|
+
return buildCatalogRows(apiKey, resolveBaseUrl(ctx.env));
|
|
117
54
|
},
|
|
118
55
|
});
|
|
119
|
-
// eslint-disable-next-line no-console
|
|
120
|
-
console.error("[runware-plugin] registerModelCatalogProvider DONE");
|
|
121
56
|
},
|
|
122
57
|
};
|
|
123
58
|
export default entry;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,GACf,MAAM,aAAa,CAAC;AAGrB,MAAM,SAAS,GAAG,2BAA2B,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,KAAK,GAAgB;IACzB,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,cAAc;IACpB,WAAW,EACT,yGAAyG;IAE3G,QAAQ,CAAC,GAAG;QACV,GAAG,CAAC,gBAAgB,CAAC;YACnB,EAAE,EAAE,WAAW;YACf,KAAK,EAAE,cAAc;YACrB,QAAQ,EAAE,yBAAyB;YACnC,OAAO,EAAE,CAAC,eAAe,EAAE,gBAAgB,CAAC;YAC5C,IAAI,EAAE,EAAE;YACR,OAAO,EAAE;gBACP,KAAK,EAAE,QAAQ;gBACf,GAAG,EAAE,KAAK,EAAE,GAAmB,EAAE,EAAE;oBACjC,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;oBAClC,IAAI,CAAC,MAAM;wBAAE,OAAO,IAAI,CAAC;oBACzB,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;oBACtE,OAAO,EAAE,QAAQ,EAAE,CAAC;gBACtB,CAAC;aACF;SACF,CAAC,CAAC;QAEH,GAAG,CAAC,4BAA4B,CAAC;YAC/B,QAAQ,EAAE,WAAW;YACrB,KAAK,EAAE,CAAC,MAAM,CAAC;YACf,WAAW,EAAE,KAAK,EAAE,GAAmB,EAAE,EAAE;gBACzC,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;gBAClC,IAAI,CAAC,MAAM;oBAAE,OAAO,IAAI,CAAC;gBACzB,OAAO,gBAAgB,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3D,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
package/dist/models.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-building primitives shared between the plugin's register() entry
|
|
3
|
+
* (src/index.ts) and the provider-discovery default export
|
|
4
|
+
* (src/provider-discovery.ts).
|
|
5
|
+
*
|
|
6
|
+
* The Runware gateway is OpenAI-compatible — every model accepts the same
|
|
7
|
+
* chat-completions request shape. Context window, max tokens, cost, and
|
|
8
|
+
* reasoning behaviour are uniform across the catalog (Runware itself does
|
|
9
|
+
* not expose per-model metadata via /v1/models — only ids). When that
|
|
10
|
+
* changes upstream, refine the per-model overrides here in one place.
|
|
11
|
+
*/
|
|
12
|
+
export declare const PROVIDER_ID = "runware";
|
|
13
|
+
export declare const PROVIDER_LABEL = "Runware";
|
|
14
|
+
export declare const DEFAULT_BASE_URL = "https://api.runware.ai/v1";
|
|
15
|
+
export declare const API_KEY_ENV_VAR = "RUNWARE_API_KEY";
|
|
16
|
+
export declare const BASE_URL_ENV_VAR = "RUNWARE_BASE_URL";
|
|
17
|
+
declare const MODEL_PARAMS: {
|
|
18
|
+
readonly extra_body: {
|
|
19
|
+
readonly reasoning_effort: "high";
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
declare const ZERO_COST: {
|
|
23
|
+
readonly input: 0;
|
|
24
|
+
readonly output: 0;
|
|
25
|
+
readonly cacheRead: 0;
|
|
26
|
+
readonly cacheWrite: 0;
|
|
27
|
+
};
|
|
28
|
+
export interface ModelEntry {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
reasoning: true;
|
|
32
|
+
input: ["text"];
|
|
33
|
+
contextWindow: number;
|
|
34
|
+
maxTokens: number;
|
|
35
|
+
cost: typeof ZERO_COST;
|
|
36
|
+
params: typeof MODEL_PARAMS;
|
|
37
|
+
}
|
|
38
|
+
export interface ProviderShape {
|
|
39
|
+
baseUrl: string;
|
|
40
|
+
apiKey: string;
|
|
41
|
+
api: "openai-completions";
|
|
42
|
+
timeoutSeconds: number;
|
|
43
|
+
models: ModelEntry[];
|
|
44
|
+
}
|
|
45
|
+
export interface ModelCatalogRow {
|
|
46
|
+
kind: "text";
|
|
47
|
+
provider: string;
|
|
48
|
+
model: string;
|
|
49
|
+
label: string;
|
|
50
|
+
source: "live";
|
|
51
|
+
reasoning: true;
|
|
52
|
+
input: ["text"];
|
|
53
|
+
contextWindow: number;
|
|
54
|
+
maxTokens: number;
|
|
55
|
+
cost: typeof ZERO_COST;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convert a Runware model id ("anthropic-claude-opus-4-7",
|
|
59
|
+
* "qwen35_27b_fp8") into a human-readable label for catalog rows.
|
|
60
|
+
* Pure function, exported for tests.
|
|
61
|
+
*/
|
|
62
|
+
export declare function humanizeModelId(id: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve the Runware base URL — `RUNWARE_BASE_URL` env override wins,
|
|
65
|
+
* falling back to the production endpoint. `env` is the explicit context
|
|
66
|
+
* map passed by openclaw at hook time; `process.env` is the fallback for
|
|
67
|
+
* code paths invoked outside a hook (none in production, but useful in
|
|
68
|
+
* tests).
|
|
69
|
+
*/
|
|
70
|
+
export declare function resolveBaseUrl(env?: Record<string, string | undefined>): string;
|
|
71
|
+
/**
|
|
72
|
+
* Resolve the Runware API key. The env variable wins over openclaw's
|
|
73
|
+
* `ctx.resolveProviderApiKey(...)` because env is the source of truth in
|
|
74
|
+
* the managed-deployment scenario where this plugin actually runs: each
|
|
75
|
+
* instance pod gets `RUNWARE_API_KEY` injected from a Kubernetes Secret
|
|
76
|
+
* that the openclaw-manager keeps in sync with the Runware Admin API.
|
|
77
|
+
*
|
|
78
|
+
* `ctx.resolveProviderApiKey` can return a stale value — openclaw's
|
|
79
|
+
* credentials resolver caches keys from auto-enable / config snapshots /
|
|
80
|
+
* legacy auth-profile state, and we observed it returning an old (revoked)
|
|
81
|
+
* key here even though the secret was rotated and the new key is live in
|
|
82
|
+
* env. Reversing the order makes env authoritative and falls back to the
|
|
83
|
+
* runtime-resolved key only when env is empty (e.g. running outside a
|
|
84
|
+
* managed deployment, where the user configured the key via the wizard).
|
|
85
|
+
*/
|
|
86
|
+
export declare function resolveApiKey(ctx: {
|
|
87
|
+
resolveProviderApiKey?: (providerId: string) => {
|
|
88
|
+
apiKey?: string;
|
|
89
|
+
};
|
|
90
|
+
env?: Record<string, string | undefined>;
|
|
91
|
+
}): string | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* Build the provider shape openclaw needs for both the catalog surface
|
|
94
|
+
* (so the UI picker / list can enumerate models) and the inference path
|
|
95
|
+
* (so the OpenAI-compatible client knows the apiKey + baseUrl). Fetches
|
|
96
|
+
* `/v1/models` from Runware via the TTL cache in `catalog.ts`.
|
|
97
|
+
*/
|
|
98
|
+
export declare function buildProvider(apiKey: string, baseUrl: string): Promise<ProviderShape>;
|
|
99
|
+
/**
|
|
100
|
+
* Build the catalog row list for `api.registerModelCatalogProvider`'s
|
|
101
|
+
* `liveCatalog` hook (text-kind rows for the UI picker). Same source of
|
|
102
|
+
* truth as `buildProvider` — they always reflect the same live `/v1/models`
|
|
103
|
+
* response.
|
|
104
|
+
*/
|
|
105
|
+
export declare function buildCatalogRows(apiKey: string, baseUrl: string): Promise<ModelCatalogRow[]>;
|
|
106
|
+
export {};
|
|
107
|
+
//# sourceMappingURL=models.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,eAAO,MAAM,WAAW,YAAY,CAAC;AACrC,eAAO,MAAM,cAAc,YAAY,CAAC;AACxC,eAAO,MAAM,gBAAgB,8BAA8B,CAAC;AAC5D,eAAO,MAAM,eAAe,oBAAoB,CAAC;AACjD,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAKnD,QAAA,MAAM,YAAY;;;;CAAwD,CAAC;AAC3E,QAAA,MAAM,SAAS;;;;;CAAgE,CAAC;AAEhF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,SAAS,CAAC;IACvB,MAAM,EAAE,OAAO,YAAY,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,oBAAoB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,SAAS,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAI/E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE;IACjC,qBAAqB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC1C,GAAG,MAAM,GAAG,SAAS,CAKrB;AA8BD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,CAAC,CASxB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,eAAe,EAAE,CAAC,CAG5B"}
|
package/dist/models.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-building primitives shared between the plugin's register() entry
|
|
3
|
+
* (src/index.ts) and the provider-discovery default export
|
|
4
|
+
* (src/provider-discovery.ts).
|
|
5
|
+
*
|
|
6
|
+
* The Runware gateway is OpenAI-compatible — every model accepts the same
|
|
7
|
+
* chat-completions request shape. Context window, max tokens, cost, and
|
|
8
|
+
* reasoning behaviour are uniform across the catalog (Runware itself does
|
|
9
|
+
* not expose per-model metadata via /v1/models — only ids). When that
|
|
10
|
+
* changes upstream, refine the per-model overrides here in one place.
|
|
11
|
+
*/
|
|
12
|
+
import { fetchModelIds } from "./catalog.js";
|
|
13
|
+
export const PROVIDER_ID = "runware";
|
|
14
|
+
export const PROVIDER_LABEL = "Runware";
|
|
15
|
+
export const DEFAULT_BASE_URL = "https://api.runware.ai/v1";
|
|
16
|
+
export const API_KEY_ENV_VAR = "RUNWARE_API_KEY";
|
|
17
|
+
export const BASE_URL_ENV_VAR = "RUNWARE_BASE_URL";
|
|
18
|
+
const REQUEST_TIMEOUT_SECONDS = 600;
|
|
19
|
+
const MODEL_CONTEXT_WINDOW = 200_000;
|
|
20
|
+
const MODEL_MAX_TOKENS = 32_768;
|
|
21
|
+
const MODEL_PARAMS = { extra_body: { reasoning_effort: "high" } };
|
|
22
|
+
const ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
23
|
+
/**
|
|
24
|
+
* Convert a Runware model id ("anthropic-claude-opus-4-7",
|
|
25
|
+
* "qwen35_27b_fp8") into a human-readable label for catalog rows.
|
|
26
|
+
* Pure function, exported for tests.
|
|
27
|
+
*/
|
|
28
|
+
export function humanizeModelId(id) {
|
|
29
|
+
return id
|
|
30
|
+
.replace(/[-_:@]/g, " ")
|
|
31
|
+
.replace(/\bfp8\b/gi, "FP8")
|
|
32
|
+
.trim()
|
|
33
|
+
.split(/\s+/)
|
|
34
|
+
.map((word) => (word.length > 0 ? word[0].toUpperCase() + word.slice(1) : word))
|
|
35
|
+
.join(" ");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the Runware base URL — `RUNWARE_BASE_URL` env override wins,
|
|
39
|
+
* falling back to the production endpoint. `env` is the explicit context
|
|
40
|
+
* map passed by openclaw at hook time; `process.env` is the fallback for
|
|
41
|
+
* code paths invoked outside a hook (none in production, but useful in
|
|
42
|
+
* tests).
|
|
43
|
+
*/
|
|
44
|
+
export function resolveBaseUrl(env) {
|
|
45
|
+
const raw = env?.[BASE_URL_ENV_VAR] ?? process.env[BASE_URL_ENV_VAR];
|
|
46
|
+
const trimmed = typeof raw === "string" ? raw.trim() : "";
|
|
47
|
+
return trimmed.length > 0 ? trimmed : DEFAULT_BASE_URL;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the Runware API key. The env variable wins over openclaw's
|
|
51
|
+
* `ctx.resolveProviderApiKey(...)` because env is the source of truth in
|
|
52
|
+
* the managed-deployment scenario where this plugin actually runs: each
|
|
53
|
+
* instance pod gets `RUNWARE_API_KEY` injected from a Kubernetes Secret
|
|
54
|
+
* that the openclaw-manager keeps in sync with the Runware Admin API.
|
|
55
|
+
*
|
|
56
|
+
* `ctx.resolveProviderApiKey` can return a stale value — openclaw's
|
|
57
|
+
* credentials resolver caches keys from auto-enable / config snapshots /
|
|
58
|
+
* legacy auth-profile state, and we observed it returning an old (revoked)
|
|
59
|
+
* key here even though the secret was rotated and the new key is live in
|
|
60
|
+
* env. Reversing the order makes env authoritative and falls back to the
|
|
61
|
+
* runtime-resolved key only when env is empty (e.g. running outside a
|
|
62
|
+
* managed deployment, where the user configured the key via the wizard).
|
|
63
|
+
*/
|
|
64
|
+
export function resolveApiKey(ctx) {
|
|
65
|
+
const fromEnv = ctx.env?.[API_KEY_ENV_VAR] ?? process.env[API_KEY_ENV_VAR];
|
|
66
|
+
if (typeof fromEnv === "string" && fromEnv.length > 0)
|
|
67
|
+
return fromEnv;
|
|
68
|
+
const fromAuth = ctx.resolveProviderApiKey?.(PROVIDER_ID).apiKey;
|
|
69
|
+
return typeof fromAuth === "string" && fromAuth.length > 0 ? fromAuth : undefined;
|
|
70
|
+
}
|
|
71
|
+
function buildModelEntry(id) {
|
|
72
|
+
return {
|
|
73
|
+
id,
|
|
74
|
+
name: humanizeModelId(id),
|
|
75
|
+
reasoning: true,
|
|
76
|
+
input: ["text"],
|
|
77
|
+
contextWindow: MODEL_CONTEXT_WINDOW,
|
|
78
|
+
maxTokens: MODEL_MAX_TOKENS,
|
|
79
|
+
cost: ZERO_COST,
|
|
80
|
+
params: MODEL_PARAMS,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function buildCatalogRow(id) {
|
|
84
|
+
return {
|
|
85
|
+
kind: "text",
|
|
86
|
+
provider: PROVIDER_ID,
|
|
87
|
+
model: id,
|
|
88
|
+
label: humanizeModelId(id),
|
|
89
|
+
source: "live",
|
|
90
|
+
reasoning: true,
|
|
91
|
+
input: ["text"],
|
|
92
|
+
contextWindow: MODEL_CONTEXT_WINDOW,
|
|
93
|
+
maxTokens: MODEL_MAX_TOKENS,
|
|
94
|
+
cost: ZERO_COST,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Build the provider shape openclaw needs for both the catalog surface
|
|
99
|
+
* (so the UI picker / list can enumerate models) and the inference path
|
|
100
|
+
* (so the OpenAI-compatible client knows the apiKey + baseUrl). Fetches
|
|
101
|
+
* `/v1/models` from Runware via the TTL cache in `catalog.ts`.
|
|
102
|
+
*/
|
|
103
|
+
export async function buildProvider(apiKey, baseUrl) {
|
|
104
|
+
const ids = await fetchModelIds(baseUrl, apiKey);
|
|
105
|
+
return {
|
|
106
|
+
baseUrl,
|
|
107
|
+
apiKey,
|
|
108
|
+
api: "openai-completions",
|
|
109
|
+
timeoutSeconds: REQUEST_TIMEOUT_SECONDS,
|
|
110
|
+
models: ids.map(buildModelEntry),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Build the catalog row list for `api.registerModelCatalogProvider`'s
|
|
115
|
+
* `liveCatalog` hook (text-kind rows for the UI picker). Same source of
|
|
116
|
+
* truth as `buildProvider` — they always reflect the same live `/v1/models`
|
|
117
|
+
* response.
|
|
118
|
+
*/
|
|
119
|
+
export async function buildCatalogRows(apiKey, baseUrl) {
|
|
120
|
+
const ids = await fetchModelIds(baseUrl, apiKey);
|
|
121
|
+
return ids.map(buildCatalogRow);
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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"}
|
package/dist/openclaw-api.d.ts
CHANGED
|
@@ -1,49 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Local description of the OpenClaw plugin API surface we
|
|
3
|
-
*
|
|
4
|
-
* a contract,
|
|
2
|
+
* Local description of the OpenClaw plugin API surface we depend on. We
|
|
3
|
+
* intentionally do not import these types from the `openclaw` package at
|
|
4
|
+
* runtime — the plugin defines a contract against the runtime, it is not
|
|
5
|
+
* a downstream consumer of openclaw's TypeScript types. Keeping the surface
|
|
6
|
+
* minimal here also lets us track exactly which hooks we touch.
|
|
7
|
+
*/
|
|
8
|
+
import type { ModelCatalogRow } from "./models.js";
|
|
9
|
+
/**
|
|
10
|
+
* Context passed to plugin hooks (`registerProvider.catalog.run`,
|
|
11
|
+
* `registerModelCatalogProvider.liveCatalog`, and the
|
|
12
|
+
* `providerCatalogEntry.catalog.run` discovery hook). Optional fields are
|
|
13
|
+
* not guaranteed across openclaw versions.
|
|
5
14
|
*/
|
|
6
|
-
export type Modality = "text";
|
|
7
|
-
export interface ModelCost {
|
|
8
|
-
input: number;
|
|
9
|
-
output: number;
|
|
10
|
-
cacheRead: number;
|
|
11
|
-
cacheWrite: number;
|
|
12
|
-
}
|
|
13
15
|
export interface CatalogContext {
|
|
14
|
-
resolveProviderApiKey
|
|
16
|
+
resolveProviderApiKey?: (providerId: string) => {
|
|
15
17
|
apiKey?: string;
|
|
16
18
|
};
|
|
17
19
|
env?: Record<string, string | undefined>;
|
|
18
20
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
models: Array<{
|
|
25
|
-
id: string;
|
|
26
|
-
name: string;
|
|
27
|
-
reasoning: boolean;
|
|
28
|
-
input: Modality[];
|
|
29
|
-
contextWindow: number;
|
|
30
|
-
maxTokens: number;
|
|
31
|
-
cost: ModelCost;
|
|
32
|
-
params?: Record<string, unknown>;
|
|
33
|
-
}>;
|
|
34
|
-
}
|
|
35
|
-
export interface ModelCatalogRow {
|
|
36
|
-
kind: "text";
|
|
37
|
-
provider: string;
|
|
38
|
-
model: string;
|
|
39
|
-
label: string;
|
|
40
|
-
source: "live";
|
|
41
|
-
reasoning?: boolean;
|
|
42
|
-
input?: Modality[];
|
|
43
|
-
contextWindow?: number;
|
|
44
|
-
maxTokens?: number;
|
|
45
|
-
cost?: ModelCost;
|
|
46
|
-
}
|
|
21
|
+
/**
|
|
22
|
+
* Runtime API exposed to `register(api)`. We declare only the methods we
|
|
23
|
+
* actually call. Other methods (registerMemoryEmbeddingProvider, etc) are
|
|
24
|
+
* available on the underlying object — we just don't type them here.
|
|
25
|
+
*/
|
|
47
26
|
export interface PluginApi {
|
|
48
27
|
registerProvider: (spec: unknown) => void;
|
|
49
28
|
registerModelCatalogProvider: (spec: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openclaw-api.d.ts","sourceRoot":"","sources":["../src/openclaw-api.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"openclaw-api.d.ts","sourceRoot":"","sources":["../src/openclaw-api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,qBAAqB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC1C;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,gBAAgB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,4BAA4B,EAAE,CAAC,IAAI,EAAE;QACnC,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACrB,WAAW,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,EAAE,GAAG,IAAI,CAAC,CAAC;KACzE,KAAK,IAAI,CAAC;CACZ;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;CACpC"}
|
package/dist/openclaw-api.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Local description of the OpenClaw plugin API surface we
|
|
3
|
-
*
|
|
4
|
-
* a contract,
|
|
2
|
+
* Local description of the OpenClaw plugin API surface we depend on. We
|
|
3
|
+
* intentionally do not import these types from the `openclaw` package at
|
|
4
|
+
* runtime — the plugin defines a contract against the runtime, it is not
|
|
5
|
+
* a downstream consumer of openclaw's TypeScript types. Keeping the surface
|
|
6
|
+
* minimal here also lets us track exactly which hooks we touch.
|
|
5
7
|
*/
|
|
6
8
|
export {};
|
|
7
9
|
//# sourceMappingURL=openclaw-api.js.map
|
package/dist/openclaw-api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openclaw-api.js","sourceRoot":"","sources":["../src/openclaw-api.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"openclaw-api.js","sourceRoot":"","sources":["../src/openclaw-api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -1,32 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
import { DEFAULT_BASE_URL } from "./models.js";
|
|
2
|
+
import type { ProviderShape } from "./models.js";
|
|
3
|
+
/**
|
|
4
|
+
* Default export consumed by openclaw via the `providerCatalogEntry` field
|
|
5
|
+
* in openclaw.plugin.json. This is the surface that openclaw 2026.5.x
|
|
6
|
+
* actually calls when it needs to resolve the Runware model catalog —
|
|
7
|
+
* `catalog.run(ctx)` returns a live provider shape, populated from a
|
|
8
|
+
* fresh (TTL-cached) `GET /v1/models` against the configured Runware
|
|
9
|
+
* endpoint.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors the bundled `ollama` plugin's provider-discovery contract — see
|
|
12
|
+
* /app/dist/extensions/ollama/provider-discovery.js inside the openclaw
|
|
13
|
+
* image for the reference implementation.
|
|
14
|
+
*
|
|
15
|
+
* `order: "late"` means this hook runs after bundled providers have had a
|
|
16
|
+
* chance to register, matching how ollama declares itself.
|
|
17
|
+
*/
|
|
18
|
+
interface DiscoveryCtx {
|
|
2
19
|
env?: Record<string, string | undefined>;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
provider: {
|
|
6
|
-
baseUrl: string;
|
|
7
|
-
apiKey: string;
|
|
8
|
-
api: "openai-completions";
|
|
9
|
-
timeoutSeconds: number;
|
|
10
|
-
models: {
|
|
11
|
-
id: string;
|
|
12
|
-
name: string;
|
|
13
|
-
reasoning: boolean;
|
|
14
|
-
input: readonly ["text"];
|
|
15
|
-
contextWindow: number;
|
|
16
|
-
maxTokens: number;
|
|
17
|
-
cost: {
|
|
18
|
-
input: number;
|
|
19
|
-
output: number;
|
|
20
|
-
cacheRead: number;
|
|
21
|
-
cacheWrite: number;
|
|
22
|
-
};
|
|
23
|
-
params: {
|
|
24
|
-
readonly extra_body: {
|
|
25
|
-
readonly reasoning_effort: "high";
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
}[];
|
|
20
|
+
resolveProviderApiKey?: (providerId: string) => {
|
|
21
|
+
apiKey?: string;
|
|
29
22
|
};
|
|
23
|
+
}
|
|
24
|
+
declare function runwareCatalogRun(ctx: DiscoveryCtx): Promise<{
|
|
25
|
+
provider: ProviderShape;
|
|
30
26
|
}>;
|
|
31
27
|
declare const runwareProviderDiscovery: {
|
|
32
28
|
id: string;
|
|
@@ -36,8 +32,9 @@ declare const runwareProviderDiscovery: {
|
|
|
36
32
|
auth: never[];
|
|
37
33
|
catalog: {
|
|
38
34
|
order: "late";
|
|
39
|
-
run: typeof
|
|
35
|
+
run: typeof runwareCatalogRun;
|
|
40
36
|
};
|
|
41
37
|
};
|
|
42
38
|
export default runwareProviderDiscovery;
|
|
39
|
+
export { DEFAULT_BASE_URL };
|
|
43
40
|
//# sourceMappingURL=provider-discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-discovery.d.ts","sourceRoot":"","sources":["../src/provider-discovery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"provider-discovery.d.ts","sourceRoot":"","sources":["../src/provider-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,gBAAgB,EAMjB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;;;;;;;;;;;;;GAcG;AAEH,UAAU,YAAY;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,qBAAqB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE;AAYD,iBAAe,iBAAiB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,aAAa,CAAA;CAAE,CAAC,CAUxF;AAED,QAAA,MAAM,wBAAwB;;;;;;;;;;CAU7B,CAAC;AAEF,eAAe,wBAAwB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -1,72 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const PROVIDER_LABEL = "Runware";
|
|
4
|
-
const DEFAULT_BASE_URL = "https://api.runware.ai/v1";
|
|
5
|
-
const API_KEY_ENV_VAR = "RUNWARE_API_KEY";
|
|
6
|
-
const BASE_URL_ENV_VAR = "RUNWARE_BASE_URL";
|
|
7
|
-
const REQUEST_TIMEOUT_SECONDS = 600;
|
|
8
|
-
const MODEL_CONTEXT_WINDOW = 200_000;
|
|
9
|
-
const MODEL_MAX_TOKENS = 32_768;
|
|
10
|
-
const MODEL_PARAMS = { extra_body: { reasoning_effort: "high" } };
|
|
11
|
-
const ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
12
|
-
function getBaseUrl(env) {
|
|
13
|
-
const raw = env?.[BASE_URL_ENV_VAR] ?? process.env[BASE_URL_ENV_VAR];
|
|
14
|
-
const override = typeof raw === "string" ? raw.trim() : "";
|
|
15
|
-
return override.length > 0 ? override : DEFAULT_BASE_URL;
|
|
16
|
-
}
|
|
17
|
-
function getApiKey(env) {
|
|
18
|
-
const raw = env?.[API_KEY_ENV_VAR] ?? process.env[API_KEY_ENV_VAR];
|
|
19
|
-
return typeof raw === "string" && raw.length > 0 ? raw : undefined;
|
|
20
|
-
}
|
|
21
|
-
function humanizeModelId(id) {
|
|
22
|
-
return id
|
|
23
|
-
.replace(/[-_:@]/g, " ")
|
|
24
|
-
.replace(/\bfp8\b/gi, "FP8")
|
|
25
|
-
.trim()
|
|
26
|
-
.split(/\s+/)
|
|
27
|
-
.map((w) => (w.length > 0 ? w[0].toUpperCase() + w.slice(1) : w))
|
|
28
|
-
.join(" ");
|
|
29
|
-
}
|
|
30
|
-
async function buildProvider(ctx) {
|
|
31
|
-
// eslint-disable-next-line no-console
|
|
32
|
-
console.error("[runware-plugin] staticCatalog.run called, ctx keys:", Object.keys(ctx ?? {}));
|
|
33
|
-
const apiKey = getApiKey(ctx.env);
|
|
34
|
-
// eslint-disable-next-line no-console
|
|
35
|
-
console.error("[runware-plugin] staticCatalog apiKey:", apiKey ? "yes" : "no");
|
|
36
|
-
if (!apiKey) {
|
|
37
|
-
return {
|
|
38
|
-
provider: {
|
|
39
|
-
baseUrl: DEFAULT_BASE_URL,
|
|
40
|
-
apiKey: "",
|
|
41
|
-
api: "openai-completions",
|
|
42
|
-
timeoutSeconds: REQUEST_TIMEOUT_SECONDS,
|
|
43
|
-
models: [],
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
const baseUrl = getBaseUrl(ctx.env);
|
|
48
|
-
const ids = await fetchModelIds(baseUrl, apiKey);
|
|
49
|
-
// eslint-disable-next-line no-console
|
|
50
|
-
console.error("[runware-plugin] staticCatalog fetched", ids.length, "models");
|
|
1
|
+
import { API_KEY_ENV_VAR, BASE_URL_ENV_VAR, DEFAULT_BASE_URL, PROVIDER_ID, PROVIDER_LABEL, buildProvider, resolveApiKey, resolveBaseUrl, } from "./models.js";
|
|
2
|
+
function emptyProvider(baseUrl) {
|
|
51
3
|
return {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
models: ids.map((id) => ({
|
|
58
|
-
id,
|
|
59
|
-
name: humanizeModelId(id),
|
|
60
|
-
reasoning: true,
|
|
61
|
-
input: ["text"],
|
|
62
|
-
contextWindow: MODEL_CONTEXT_WINDOW,
|
|
63
|
-
maxTokens: MODEL_MAX_TOKENS,
|
|
64
|
-
cost: ZERO_COST,
|
|
65
|
-
params: MODEL_PARAMS,
|
|
66
|
-
})),
|
|
67
|
-
},
|
|
4
|
+
baseUrl,
|
|
5
|
+
apiKey: "",
|
|
6
|
+
api: "openai-completions",
|
|
7
|
+
timeoutSeconds: 600,
|
|
8
|
+
models: [],
|
|
68
9
|
};
|
|
69
10
|
}
|
|
11
|
+
async function runwareCatalogRun(ctx) {
|
|
12
|
+
const baseUrl = resolveBaseUrl(ctx.env);
|
|
13
|
+
const apiKey = resolveApiKey(ctx);
|
|
14
|
+
// No API key reachable yet (e.g. the gateway is starting up before the
|
|
15
|
+
// env secret is injected, or the user has not configured Runware): return
|
|
16
|
+
// an empty provider shape so openclaw treats the catalog as "known but
|
|
17
|
+
// currently unpopulated" rather than crashing. The next invocation will
|
|
18
|
+
// re-resolve and fill in models once the key is present.
|
|
19
|
+
if (!apiKey)
|
|
20
|
+
return { provider: emptyProvider(baseUrl) };
|
|
21
|
+
return { provider: await buildProvider(apiKey, baseUrl) };
|
|
22
|
+
}
|
|
70
23
|
const runwareProviderDiscovery = {
|
|
71
24
|
id: PROVIDER_ID,
|
|
72
25
|
label: PROVIDER_LABEL,
|
|
@@ -75,8 +28,9 @@ const runwareProviderDiscovery = {
|
|
|
75
28
|
auth: [],
|
|
76
29
|
catalog: {
|
|
77
30
|
order: "late",
|
|
78
|
-
run:
|
|
31
|
+
run: runwareCatalogRun,
|
|
79
32
|
},
|
|
80
33
|
};
|
|
81
34
|
export default runwareProviderDiscovery;
|
|
35
|
+
export { DEFAULT_BASE_URL };
|
|
82
36
|
//# sourceMappingURL=provider-discovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-discovery.js","sourceRoot":"","sources":["../src/provider-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"provider-discovery.js","sourceRoot":"","sources":["../src/provider-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,aAAa,EACb,aAAa,EACb,cAAc,GACf,MAAM,aAAa,CAAC;AAwBrB,SAAS,aAAa,CAAC,OAAe;IACpC,OAAO;QACL,OAAO;QACP,MAAM,EAAE,EAAE;QACV,GAAG,EAAE,oBAAoB;QACzB,cAAc,EAAE,GAAG;QACnB,MAAM,EAAE,EAAE;KACX,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,GAAiB;IAChD,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAClC,uEAAuE;IACvE,0EAA0E;IAC1E,uEAAuE;IACvE,wEAAwE;IACxE,yDAAyD;IACzD,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;IACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,MAAM,wBAAwB,GAAG;IAC/B,EAAE,EAAE,WAAW;IACf,KAAK,EAAE,cAAc;IACrB,QAAQ,EAAE,yBAAyB;IACnC,OAAO,EAAE,CAAC,eAAe,EAAE,gBAAgB,CAAC;IAC5C,IAAI,EAAE,EAAE;IACR,OAAO,EAAE;QACP,KAAK,EAAE,MAAe;QACtB,GAAG,EAAE,iBAAiB;KACvB;CACF,CAAC;AAEF,eAAe,wBAAwB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "runware-openclaw-provider",
|
|
3
|
-
"name": "@runware/openclaw-provider",
|
|
4
|
-
"version": "0.1.0",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"configSchema": {
|
|
7
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
8
|
-
"type": "object",
|
|
9
|
-
"additionalProperties": false,
|
|
10
|
-
"properties": {}
|
|
11
|
-
},
|
|
12
3
|
"activation": { "onStartup": true },
|
|
13
4
|
"enabledByDefault": true,
|
|
14
5
|
"providers": ["runware"],
|
|
15
6
|
"providerCatalogEntry": "./dist/provider-discovery.js",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
7
|
+
"setup": {
|
|
8
|
+
"providers": [
|
|
9
|
+
{ "id": "runware", "envVars": ["RUNWARE_API_KEY"] }
|
|
10
|
+
]
|
|
18
11
|
},
|
|
19
12
|
"providerRequest": {
|
|
20
13
|
"providers": {
|
|
@@ -27,6 +20,12 @@
|
|
|
27
20
|
"modelPricing": {
|
|
28
21
|
"providers": { "runware": { "external": false } }
|
|
29
22
|
},
|
|
23
|
+
"configSchema": {
|
|
24
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
25
|
+
"type": "object",
|
|
26
|
+
"additionalProperties": false,
|
|
27
|
+
"properties": {}
|
|
28
|
+
},
|
|
30
29
|
"openclaw": {
|
|
31
30
|
"id": "runware-openclaw-provider",
|
|
32
31
|
"extensions": ["./dist/index.js"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teith/openclaw-runware-provider",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"description": "OpenClaw provider plugin for Runware — unified OpenAI-compatible access to Claude, GPT, Gemini, Qwen, GLM, MiniMax, Kimi, and Gemma.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|