@get-bb/plugin-sdk 0.5.15 → 0.5.23

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.
@@ -1127,48 +1127,17 @@ function validateProviderFallbackModels(providerId, value) {
1127
1127
  }
1128
1128
  return Object.freeze(normalized);
1129
1129
  }
1130
- var AI_SERVICE_KINDS = /* @__PURE__ */ new Set(["inference", "voice"]);
1131
- var SERVER_DIRECT_AI_SERVICE_IDS = Object.freeze([
1132
- "openai",
1133
- "amazon-bedrock",
1134
- "ant-ling",
1135
- "anthropic",
1136
- "azure-openai-responses",
1137
- "baseten",
1138
- "cerebras",
1139
- "cloudflare-ai-gateway",
1140
- "cloudflare-workers-ai",
1141
- "deepseek",
1142
- "fireworks",
1143
- "github-copilot",
1144
- "google",
1145
- "google-vertex",
1146
- "groq",
1147
- "huggingface",
1148
- "kimi-coding",
1149
- "minimax",
1150
- "minimax-cn",
1151
- "mistral",
1152
- "moonshotai",
1153
- "moonshotai-cn",
1154
- "nvidia",
1155
- "openai-codex",
1156
- "opencode",
1157
- "opencode-go",
1158
- "openrouter",
1159
- "qwen-token-plan",
1160
- "qwen-token-plan-cn",
1161
- "radius",
1162
- "together",
1163
- "vercel-ai-gateway",
1164
- "xai",
1165
- "xiaomi",
1166
- "xiaomi-token-plan-ams",
1167
- "xiaomi-token-plan-cn",
1168
- "xiaomi-token-plan-sgp",
1169
- "zai",
1170
- "zai-coding-cn"
1130
+ var RESERVED_AI_SERVICE_IDS = /* @__PURE__ */ new Set([
1131
+ "automatic",
1132
+ "off"
1171
1133
  ]);
1134
+ function optionalAiServiceFunction(id, name, value) {
1135
+ if (value === void 0) return null;
1136
+ if (typeof value !== "function") {
1137
+ throw new Error(`AI service "${id}" ${name} must be a function`);
1138
+ }
1139
+ return value;
1140
+ }
1172
1141
  function validatePluginAiServiceDeclaration(declaration) {
1173
1142
  if (typeof declaration !== "object" || declaration === null) {
1174
1143
  throw new Error("AI service declaration must be an object");
@@ -1179,50 +1148,35 @@ function validatePluginAiServiceDeclaration(declaration) {
1179
1148
  `invalid AI service id ${JSON.stringify(id)} \u2014 use 2-64 lowercase letters, digits, and "-", starting with a letter or digit`
1180
1149
  );
1181
1150
  }
1151
+ if (RESERVED_AI_SERVICE_IDS.has(id)) {
1152
+ throw new Error(
1153
+ `AI service id "${id}" is reserved: bb uses "automatic" and "off" as selection modes. Choose another id.`
1154
+ );
1155
+ }
1182
1156
  const displayName = typeof declaration.displayName === "string" ? declaration.displayName.trim() : "";
1183
1157
  if (displayName.length === 0 || displayName.length > 64) {
1184
1158
  throw new Error(`AI service "${id}" displayName must be 1-64 characters`);
1185
1159
  }
1186
- const kinds = declaration.kinds;
1187
- if (!Array.isArray(kinds) || kinds.length === 0) {
1188
- throw new Error(`AI service "${id}" must declare at least one kind`);
1189
- }
1190
- const seen = /* @__PURE__ */ new Set();
1191
- for (const kind of kinds) {
1192
- if (typeof kind !== "string" || !AI_SERVICE_KINDS.has(kind)) {
1193
- throw new Error(
1194
- `AI service "${id}" kind ${JSON.stringify(kind)} is not one of: ${[...AI_SERVICE_KINDS].join(", ")}`
1195
- );
1196
- }
1197
- if (seen.has(kind)) {
1198
- throw new Error(`AI service "${id}" declares kind "${kind}" twice`);
1199
- }
1200
- seen.add(kind);
1201
- }
1202
- return Object.freeze({
1160
+ const complete = optionalAiServiceFunction(
1203
1161
  id,
1204
- displayName,
1205
- kinds: Object.freeze([...seen])
1206
- });
1207
- }
1208
- function assertAiServiceRegistrable(args) {
1209
- if (SERVER_DIRECT_AI_SERVICE_IDS.includes(args.id)) {
1162
+ "complete",
1163
+ declaration.complete
1164
+ );
1165
+ const transcribe = optionalAiServiceFunction(
1166
+ id,
1167
+ "transcribe",
1168
+ declaration.transcribe
1169
+ );
1170
+ const status = optionalAiServiceFunction(id, "status", declaration.status);
1171
+ if (complete === null && transcribe === null) {
1210
1172
  throw new Error(
1211
- `AI service id "${args.id}" is reserved: the server serves it directly, so a plugin cannot register it`
1173
+ `AI service "${id}" must declare complete, transcribe, or both`
1212
1174
  );
1213
1175
  }
1214
- if (args.hostArtifact !== null) {
1215
- return { artifact: args.hostArtifact, problem: null };
1216
- }
1217
- if (args.hostArtifactProblem !== null) {
1218
- return { artifact: null, problem: args.hostArtifactProblem };
1219
- }
1220
- throw new Error(
1221
- `AI service "${args.id}" needs a bb.host entry to run on: this plugin declares none`
1222
- );
1176
+ return Object.freeze({ id, displayName, complete, transcribe, status });
1223
1177
  }
1224
1178
  function aiServiceAlreadyRegisteredMessage(id) {
1225
- return `AI service "${id}" is already registered; a plugin cannot shadow an existing service.`;
1179
+ return `AI service "${id}" is already registered by this plugin.`;
1226
1180
  }
1227
1181
  function providerAlreadyRegisteredMessage(id) {
1228
1182
  return `Provider "${id}" is already registered; a plugin cannot shadow an existing provider.`;
@@ -3237,20 +3191,22 @@ function createFakePluginHostInternal(options, sharedState) {
3237
3191
  register(declaration) {
3238
3192
  assertLive();
3239
3193
  const normalized = validatePluginAiServiceDeclaration(declaration);
3240
- assertAiServiceRegistrable({
3241
- id: normalized.id,
3242
- hostArtifact: options.experimental_hostEntry === false ? null : "declared",
3243
- hostArtifactProblem: null
3244
- });
3245
3194
  if (aiServiceRegistrations.some((existing) => existing.id === normalized.id)) {
3246
3195
  throw new Error(aiServiceAlreadyRegisteredMessage(normalized.id));
3247
3196
  }
3248
- aiServiceRegistrations.push(normalized);
3197
+ const registration = Object.freeze({
3198
+ id: normalized.id,
3199
+ displayName: normalized.displayName,
3200
+ ...normalized.complete === null ? {} : { complete: normalized.complete },
3201
+ ...normalized.transcribe === null ? {} : { transcribe: normalized.transcribe },
3202
+ ...normalized.status === null ? {} : { status: normalized.status }
3203
+ });
3204
+ aiServiceRegistrations.push(registration);
3249
3205
  let disposed2 = false;
3250
3206
  const dispose = () => {
3251
3207
  if (disposed2) return;
3252
3208
  disposed2 = true;
3253
- const index = aiServiceRegistrations.indexOf(normalized);
3209
+ const index = aiServiceRegistrations.indexOf(registration);
3254
3210
  if (index !== -1) aiServiceRegistrations.splice(index, 1);
3255
3211
  };
3256
3212
  disposeHooks.push(dispose);
@@ -4493,7 +4449,7 @@ var TEST_FILE_PATTERN = /\.test\.[cm]?[jt]sx?$/u;
4493
4449
  var PRIVATE_PACKAGE_PREFIX = "@bb/";
4494
4450
  var PLUGIN_IMPORT_ALLOWLIST = [
4495
4451
  /^@get-bb\/plugin-sdk$/u,
4496
- /^@get-bb\/plugin-sdk\/(?:host|app|ai-services|provider-bridge|provider-bridge\/acp)$/u,
4452
+ /^@get-bb\/plugin-sdk\/(?:host|app|provider-bridge|provider-bridge\/acp)$/u,
4497
4453
  /^zod$/u,
4498
4454
  /^node:/u,
4499
4455
  /^\.\.?\//u
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@get-bb/plugin-sdk",
3
- "version": "0.5.15",
3
+ "version": "0.5.23",
4
4
  "homepage": "https://github.com/get-bb/bb#readme",
5
5
  "bugs": {
6
6
  "url": "https://github.com/get-bb/bb/issues"
@@ -26,12 +26,6 @@
26
26
  "import": "./dist/index.js",
27
27
  "default": "./dist/index.js"
28
28
  },
29
- "./ai-services": {
30
- "source": "./src/ai-services.ts",
31
- "types": "./bundled-types/bb-plugin-sdk-ai-services.d.ts",
32
- "import": "./dist/ai-services.js",
33
- "default": "./dist/ai-services.js"
34
- },
35
29
  "./provider-bridge": {
36
30
  "source": "./src/provider-bridge.ts",
37
31
  "types": "./bundled-types/bb-plugin-sdk-provider-bridge.d.ts",
@@ -134,6 +128,7 @@
134
128
  "typecheck": "tsc --noEmit"
135
129
  },
136
130
  "dependencies": {
131
+ "cross-spawn": "^7.0.6",
137
132
  "zod": "^4.3.6"
138
133
  },
139
134
  "devDependencies": {
@@ -1,141 +0,0 @@
1
- // Portable type declarations for `@get-bb/plugin-sdk`. Unpublished BB
2
- // workspace contracts are flattened; public subpaths may reuse the
3
- // package root without requiring any other @bb/* package.
4
- //
5
- // Confused by the API, or need a symbol that isn't here? Clone the BB repo
6
- // and read the real source: https://github.com/get-bb/bb
7
-
8
- import { z } from 'zod';
9
-
10
- interface JsonObject {
11
- [key: string]: JsonValue;
12
- }
13
- type JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;
14
-
15
- /** Why a call did not produce a result; core's retry policy keys on it. */
16
- declare const experimental_aiServiceErrorCodeSchema: z.ZodEnum<{
17
- auth_required: "auth_required";
18
- invalid_response: "invalid_response";
19
- rate_limited: "rate_limited";
20
- request_failed: "request_failed";
21
- service_unavailable: "service_unavailable";
22
- timeout: "timeout";
23
- }>;
24
- type ExperimentalAiServiceErrorCode = z.infer<typeof experimental_aiServiceErrorCodeSchema>;
25
- declare const experimental_aiInferenceCompleteInputSchema: z.ZodObject<{
26
- model: z.ZodString;
27
- outputSchema: z.ZodType<JsonObject, unknown, z.core.$ZodTypeInternals<JsonObject, unknown>>;
28
- prompt: z.ZodString;
29
- reasoningEffort: z.ZodLiteral<"none">;
30
- serviceId: z.ZodString;
31
- timeoutMs: z.ZodNumber;
32
- }, z.core.$strict>;
33
- type ExperimentalAiInferenceCompleteInput = z.infer<typeof experimental_aiInferenceCompleteInputSchema>;
34
- declare const experimental_aiInferenceCompleteOutputSchema: z.ZodUnion<readonly [z.ZodObject<{
35
- model: z.ZodString;
36
- ok: z.ZodLiteral<true>;
37
- value: z.ZodType<JsonObject, unknown, z.core.$ZodTypeInternals<JsonObject, unknown>>;
38
- }, z.core.$strict>, z.ZodObject<{
39
- code: z.ZodEnum<{
40
- auth_required: "auth_required";
41
- invalid_response: "invalid_response";
42
- rate_limited: "rate_limited";
43
- request_failed: "request_failed";
44
- service_unavailable: "service_unavailable";
45
- timeout: "timeout";
46
- }>;
47
- message: z.ZodString;
48
- ok: z.ZodLiteral<false>;
49
- }, z.core.$strict>]>;
50
- type ExperimentalAiInferenceCompleteOutput = z.infer<typeof experimental_aiInferenceCompleteOutputSchema>;
51
- declare const experimental_aiVoiceTranscribeInputSchema: z.ZodObject<{
52
- audioBase64: z.ZodString;
53
- filename: z.ZodString;
54
- mimeType: z.ZodString;
55
- model: z.ZodString;
56
- prompt: z.ZodNullable<z.ZodString>;
57
- serviceId: z.ZodString;
58
- timeoutMs: z.ZodNumber;
59
- }, z.core.$strict>;
60
- type ExperimentalAiVoiceTranscribeInput = z.infer<typeof experimental_aiVoiceTranscribeInputSchema>;
61
- declare const experimental_aiVoiceTranscribeOutputSchema: z.ZodUnion<readonly [z.ZodObject<{
62
- model: z.ZodString;
63
- ok: z.ZodLiteral<true>;
64
- text: z.ZodString;
65
- }, z.core.$strict>, z.ZodObject<{
66
- code: z.ZodEnum<{
67
- auth_required: "auth_required";
68
- invalid_response: "invalid_response";
69
- rate_limited: "rate_limited";
70
- request_failed: "request_failed";
71
- service_unavailable: "service_unavailable";
72
- timeout: "timeout";
73
- }>;
74
- message: z.ZodString;
75
- ok: z.ZodLiteral<false>;
76
- }, z.core.$strict>]>;
77
- type ExperimentalAiVoiceTranscribeOutput = z.infer<typeof experimental_aiVoiceTranscribeOutputSchema>;
78
- /**
79
- * The host RPC methods an AI-service plugin implements. A plugin that
80
- * registers only `inference` still builds against the full contract; the
81
- * unregistered method may answer `{ ok: false, code: "request_failed" }`.
82
- */
83
- declare const experimental_aiServicesHostContract: {
84
- readonly "ai.inference.complete": {
85
- readonly input: z.ZodObject<{
86
- model: z.ZodString;
87
- outputSchema: z.ZodType<JsonObject, unknown, z.core.$ZodTypeInternals<JsonObject, unknown>>;
88
- prompt: z.ZodString;
89
- reasoningEffort: z.ZodLiteral<"none">;
90
- serviceId: z.ZodString;
91
- timeoutMs: z.ZodNumber;
92
- }, z.core.$strict>;
93
- readonly output: z.ZodUnion<readonly [z.ZodObject<{
94
- model: z.ZodString;
95
- ok: z.ZodLiteral<true>;
96
- value: z.ZodType<JsonObject, unknown, z.core.$ZodTypeInternals<JsonObject, unknown>>;
97
- }, z.core.$strict>, z.ZodObject<{
98
- code: z.ZodEnum<{
99
- auth_required: "auth_required";
100
- invalid_response: "invalid_response";
101
- rate_limited: "rate_limited";
102
- request_failed: "request_failed";
103
- service_unavailable: "service_unavailable";
104
- timeout: "timeout";
105
- }>;
106
- message: z.ZodString;
107
- ok: z.ZodLiteral<false>;
108
- }, z.core.$strict>]>;
109
- };
110
- readonly "ai.voice.transcribe": {
111
- readonly input: z.ZodObject<{
112
- audioBase64: z.ZodString;
113
- filename: z.ZodString;
114
- mimeType: z.ZodString;
115
- model: z.ZodString;
116
- prompt: z.ZodNullable<z.ZodString>;
117
- serviceId: z.ZodString;
118
- timeoutMs: z.ZodNumber;
119
- }, z.core.$strict>;
120
- readonly output: z.ZodUnion<readonly [z.ZodObject<{
121
- model: z.ZodString;
122
- ok: z.ZodLiteral<true>;
123
- text: z.ZodString;
124
- }, z.core.$strict>, z.ZodObject<{
125
- code: z.ZodEnum<{
126
- auth_required: "auth_required";
127
- invalid_response: "invalid_response";
128
- rate_limited: "rate_limited";
129
- request_failed: "request_failed";
130
- service_unavailable: "service_unavailable";
131
- timeout: "timeout";
132
- }>;
133
- message: z.ZodString;
134
- ok: z.ZodLiteral<false>;
135
- }, z.core.$strict>]>;
136
- };
137
- };
138
- type ExperimentalAiServicesHostContract = typeof experimental_aiServicesHostContract;
139
-
140
- export { experimental_aiInferenceCompleteInputSchema, experimental_aiInferenceCompleteOutputSchema, experimental_aiServiceErrorCodeSchema, experimental_aiServicesHostContract, experimental_aiVoiceTranscribeInputSchema, experimental_aiVoiceTranscribeOutputSchema };
141
- export type { ExperimentalAiInferenceCompleteInput, ExperimentalAiInferenceCompleteOutput, ExperimentalAiServiceErrorCode, ExperimentalAiServicesHostContract, ExperimentalAiVoiceTranscribeInput, ExperimentalAiVoiceTranscribeOutput };
@@ -1,95 +0,0 @@
1
- // src/ai-services.ts
2
- import { z as z2 } from "zod";
3
-
4
- // ../domain/src/json-value.ts
5
- import { z } from "zod";
6
- var jsonValueSchema = z.lazy(
7
- () => z.union([
8
- z.string(),
9
- z.number(),
10
- z.boolean(),
11
- z.null(),
12
- z.array(jsonValueSchema),
13
- z.record(z.string(), jsonValueSchema)
14
- ])
15
- );
16
- var jsonObjectSchema = z.record(
17
- z.string(),
18
- jsonValueSchema
19
- );
20
-
21
- // src/rpc-contract.ts
22
- function defineRpcContract(contract) {
23
- return contract;
24
- }
25
-
26
- // src/ai-services.ts
27
- var experimental_aiServiceErrorCodeSchema = z2.enum([
28
- /** The service did not answer within the request's `timeoutMs`. */
29
- "timeout",
30
- /** The upstream rejected the request for rate or quota reasons; retryable. */
31
- "rate_limited",
32
- /** The upstream is down or overloaded; retryable. */
33
- "service_unavailable",
34
- /** No usable credentials on this host; the user must sign in. Not retryable. */
35
- "auth_required",
36
- /** The upstream rejected the request (bad model, bad input, policy). Not retryable. */
37
- "request_failed",
38
- /** The upstream answered, but not with something that satisfies the request. */
39
- "invalid_response"
40
- ]);
41
- var failureSchema = z2.object({
42
- ok: z2.literal(false),
43
- code: experimental_aiServiceErrorCodeSchema,
44
- message: z2.string().min(1)
45
- }).strict();
46
- var experimental_aiInferenceCompleteInputSchema = z2.object({
47
- serviceId: z2.string().min(1),
48
- /** The model segment of the user's `<serviceId>/<model>` setting. */
49
- model: z2.string().min(1),
50
- /** Helper inference is short and latency-bound; no reasoning. */
51
- reasoningEffort: z2.literal("none"),
52
- prompt: z2.string().min(1),
53
- /** A JSON Schema object the structured result must satisfy. */
54
- outputSchema: jsonObjectSchema,
55
- timeoutMs: z2.number().int().positive()
56
- }).strict();
57
- var experimental_aiInferenceCompleteOutputSchema = z2.union([
58
- z2.object({
59
- ok: z2.literal(true),
60
- model: z2.string().min(1),
61
- value: jsonObjectSchema
62
- }).strict(),
63
- failureSchema
64
- ]);
65
- var experimental_aiVoiceTranscribeInputSchema = z2.object({
66
- serviceId: z2.string().min(1),
67
- model: z2.string().min(1),
68
- audioBase64: z2.string().min(1),
69
- mimeType: z2.string().min(1),
70
- filename: z2.string().min(1),
71
- prompt: z2.string().nullable(),
72
- timeoutMs: z2.number().int().positive()
73
- }).strict();
74
- var experimental_aiVoiceTranscribeOutputSchema = z2.union([
75
- z2.object({ ok: z2.literal(true), model: z2.string().min(1), text: z2.string() }).strict(),
76
- failureSchema
77
- ]);
78
- var experimental_aiServicesHostContract = defineRpcContract({
79
- "ai.inference.complete": {
80
- input: experimental_aiInferenceCompleteInputSchema,
81
- output: experimental_aiInferenceCompleteOutputSchema
82
- },
83
- "ai.voice.transcribe": {
84
- input: experimental_aiVoiceTranscribeInputSchema,
85
- output: experimental_aiVoiceTranscribeOutputSchema
86
- }
87
- });
88
- export {
89
- experimental_aiInferenceCompleteInputSchema,
90
- experimental_aiInferenceCompleteOutputSchema,
91
- experimental_aiServiceErrorCodeSchema,
92
- experimental_aiServicesHostContract,
93
- experimental_aiVoiceTranscribeInputSchema,
94
- experimental_aiVoiceTranscribeOutputSchema
95
- };