@get-bb/plugin-sdk 0.4.10 → 0.4.12
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/bundled-types/bb-plugin-sdk-app.d.ts +131 -8
- package/bundled-types/bb-plugin-sdk-internal-host-policy.d.ts +165 -9
- package/bundled-types/bb-plugin-sdk-provider-bridge-testing.d.ts +3314 -0
- package/bundled-types/bb-plugin-sdk-provider-bridge.d.ts +1114 -371
- package/bundled-types/bb-plugin-sdk-testing-app.d.ts +6 -1
- package/bundled-types/bb-plugin-sdk.d.ts +1445 -277
- package/dist/app.js +2 -0
- package/dist/internal/host-policy.js +369 -10
- package/dist/provider-bridge-testing.js +5777 -0
- package/dist/provider-bridge.js +2697 -2083
- package/dist/testing/app.js +11 -1
- package/dist/testing/index.js +384 -27
- package/package.json +7 -1
package/dist/testing/app.js
CHANGED
|
@@ -982,6 +982,7 @@ function TestDiff({
|
|
|
982
982
|
view = "unified",
|
|
983
983
|
overflow = "scroll",
|
|
984
984
|
showLineNumbers = true,
|
|
985
|
+
experimental_fullFileContents,
|
|
985
986
|
className
|
|
986
987
|
}) {
|
|
987
988
|
return /* @__PURE__ */ jsx(
|
|
@@ -992,6 +993,7 @@ function TestDiff({
|
|
|
992
993
|
"data-view": view,
|
|
993
994
|
"data-overflow": overflow,
|
|
994
995
|
"data-show-line-numbers": showLineNumbers ? "true" : "false",
|
|
996
|
+
"data-has-full-file-contents": experimental_fullFileContents === void 0 ? "false" : "true",
|
|
995
997
|
className,
|
|
996
998
|
children: patch
|
|
997
999
|
}
|
|
@@ -1090,6 +1092,9 @@ var testPluginSdkApp = {
|
|
|
1090
1092
|
experimental_useSidebarThreads() {
|
|
1091
1093
|
return useSlotEnv("experimental_useSidebarThreads").sidebarThreads;
|
|
1092
1094
|
},
|
|
1095
|
+
experimental_useProviders() {
|
|
1096
|
+
return useSlotEnv("experimental_useProviders").providers;
|
|
1097
|
+
},
|
|
1093
1098
|
experimental_useSidebarThreadActions() {
|
|
1094
1099
|
return useSlotEnv("experimental_useSidebarThreadActions").sidebarActions;
|
|
1095
1100
|
},
|
|
@@ -1396,6 +1401,10 @@ function renderSlot(registration, props, options = {}) {
|
|
|
1396
1401
|
threads: options.sidebarThreads?.threads ?? [],
|
|
1397
1402
|
projects: options.sidebarThreads?.projects ?? []
|
|
1398
1403
|
};
|
|
1404
|
+
const providers = {
|
|
1405
|
+
status: options.providers?.status ?? "ready",
|
|
1406
|
+
providers: options.providers?.providers ?? []
|
|
1407
|
+
};
|
|
1399
1408
|
const sidebarActions = {
|
|
1400
1409
|
open(threadId2, openOptions) {
|
|
1401
1410
|
sidebarActionCalls.push({
|
|
@@ -1579,7 +1588,8 @@ ${block}
|
|
|
1579
1588
|
sidebarThreads,
|
|
1580
1589
|
sidebarActions,
|
|
1581
1590
|
sidebarActionCalls,
|
|
1582
|
-
sidebarPullRequests
|
|
1591
|
+
sidebarPullRequests,
|
|
1592
|
+
providers
|
|
1583
1593
|
};
|
|
1584
1594
|
const releaseComposerOwnership = () => {
|
|
1585
1595
|
if (!composerOwnership.active) return;
|
package/dist/testing/index.js
CHANGED
|
@@ -268,7 +268,7 @@ function validateProviderLiteralArray(args) {
|
|
|
268
268
|
}
|
|
269
269
|
return Object.freeze(normalized);
|
|
270
270
|
}
|
|
271
|
-
function normalizeProviderBridgeOptions(providerId, value) {
|
|
271
|
+
function normalizeProviderBridgeOptions(providerId, value, label = "experimental_bridgeOptions") {
|
|
272
272
|
const active = /* @__PURE__ */ new Set();
|
|
273
273
|
function visit(current, path) {
|
|
274
274
|
if (current === null || typeof current === "string" || typeof current === "boolean") {
|
|
@@ -277,14 +277,14 @@ function normalizeProviderBridgeOptions(providerId, value) {
|
|
|
277
277
|
if (typeof current === "number") {
|
|
278
278
|
if (!Number.isFinite(current)) {
|
|
279
279
|
throw new Error(
|
|
280
|
-
`provider "${providerId}"
|
|
280
|
+
`provider "${providerId}" ${label}${path} must be finite JSON`
|
|
281
281
|
);
|
|
282
282
|
}
|
|
283
283
|
return current;
|
|
284
284
|
}
|
|
285
285
|
if (typeof current !== "object") {
|
|
286
286
|
throw new Error(
|
|
287
|
-
`provider "${providerId}"
|
|
287
|
+
`provider "${providerId}" ${label}${path} must be JSON`
|
|
288
288
|
);
|
|
289
289
|
}
|
|
290
290
|
if (active.has(current)) {
|
|
@@ -304,7 +304,7 @@ function normalizeProviderBridgeOptions(providerId, value) {
|
|
|
304
304
|
const prototype = Object.getPrototypeOf(current);
|
|
305
305
|
if (prototype !== Object.prototype && prototype !== null) {
|
|
306
306
|
throw new Error(
|
|
307
|
-
`provider "${providerId}"
|
|
307
|
+
`provider "${providerId}" ${label}${path} must contain only plain JSON objects`
|
|
308
308
|
);
|
|
309
309
|
}
|
|
310
310
|
const normalized2 = Object.fromEntries(
|
|
@@ -322,16 +322,329 @@ function normalizeProviderBridgeOptions(providerId, value) {
|
|
|
322
322
|
const normalized = visit(value, "");
|
|
323
323
|
if (normalized === null || Array.isArray(normalized) || typeof normalized !== "object") {
|
|
324
324
|
throw new Error(
|
|
325
|
-
`provider "${providerId}"
|
|
325
|
+
`provider "${providerId}" ${label} must be an object`
|
|
326
326
|
);
|
|
327
327
|
}
|
|
328
328
|
if (Buffer.byteLength(JSON.stringify(normalized), "utf8") > PLUGIN_PROVIDER_BRIDGE_OPTIONS_MAX_BYTES) {
|
|
329
329
|
throw new Error(
|
|
330
|
-
`provider "${providerId}"
|
|
330
|
+
`provider "${providerId}" ${label} exceeds ${PLUGIN_PROVIDER_BRIDGE_OPTIONS_MAX_BYTES} bytes`
|
|
331
331
|
);
|
|
332
332
|
}
|
|
333
333
|
return normalized;
|
|
334
334
|
}
|
|
335
|
+
var PROVIDER_STRING_MAX_CHARS = 512;
|
|
336
|
+
var PROVIDER_EXTENSION_KIND_NAME_PATTERN = /^[a-z0-9-]+$/u;
|
|
337
|
+
var PROVIDER_EXTENSION_KINDS_MAX = 32;
|
|
338
|
+
function requireNonBlankString(args) {
|
|
339
|
+
const { providerId, field, value } = args;
|
|
340
|
+
if (typeof value !== "string" || value.trim().length === 0 || value.length > PROVIDER_STRING_MAX_CHARS) {
|
|
341
|
+
throw new Error(
|
|
342
|
+
`provider "${providerId}" ${field} must be a non-blank string of at most ${PROVIDER_STRING_MAX_CHARS} characters`
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
return value;
|
|
346
|
+
}
|
|
347
|
+
function validateProviderStrings(providerId, value) {
|
|
348
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
349
|
+
throw new Error(
|
|
350
|
+
`provider "${providerId}" experimental_strings must be an object`
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
const record = Object.fromEntries(
|
|
354
|
+
Object.entries(value)
|
|
355
|
+
);
|
|
356
|
+
const required = (field) => requireNonBlankString({
|
|
357
|
+
providerId,
|
|
358
|
+
field: `experimental_strings.${field}`,
|
|
359
|
+
value: record[field]
|
|
360
|
+
});
|
|
361
|
+
const optional = (field) => record[field] === void 0 ? void 0 : requireNonBlankString({
|
|
362
|
+
providerId,
|
|
363
|
+
field: `experimental_strings.${field}`,
|
|
364
|
+
value: record[field]
|
|
365
|
+
});
|
|
366
|
+
let iconTint;
|
|
367
|
+
if (record.iconTint !== void 0) {
|
|
368
|
+
const tint = record.iconTint;
|
|
369
|
+
if (typeof tint !== "object" || tint === null || Array.isArray(tint)) {
|
|
370
|
+
throw new Error(
|
|
371
|
+
`provider "${providerId}" experimental_strings.iconTint must be { light, dark }`
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
const tintRecord = Object.fromEntries(
|
|
375
|
+
Object.entries(tint)
|
|
376
|
+
);
|
|
377
|
+
iconTint = Object.freeze({
|
|
378
|
+
light: requireNonBlankString({
|
|
379
|
+
providerId,
|
|
380
|
+
field: "experimental_strings.iconTint.light",
|
|
381
|
+
value: tintRecord.light
|
|
382
|
+
}),
|
|
383
|
+
dark: requireNonBlankString({
|
|
384
|
+
providerId,
|
|
385
|
+
field: "experimental_strings.iconTint.dark",
|
|
386
|
+
value: tintRecord.dark
|
|
387
|
+
})
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
const brandPrefix = optional("brandPrefix");
|
|
391
|
+
const planModeCopy = optional("planModeCopy");
|
|
392
|
+
return Object.freeze({
|
|
393
|
+
signInHint: required("signInHint"),
|
|
394
|
+
expiredHint: required("expiredHint"),
|
|
395
|
+
installUrl: required("installUrl"),
|
|
396
|
+
...brandPrefix === void 0 ? {} : { brandPrefix },
|
|
397
|
+
...planModeCopy === void 0 ? {} : { planModeCopy },
|
|
398
|
+
...iconTint === void 0 ? {} : { iconTint }
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
function validateProviderOptionDescriptors(args) {
|
|
402
|
+
const { providerId, field, value } = args;
|
|
403
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
404
|
+
throw new Error(
|
|
405
|
+
`provider "${providerId}" ${field} must be a non-empty array of { id, label, description? }`
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
const seen = /* @__PURE__ */ new Set();
|
|
409
|
+
const normalized = value.map(
|
|
410
|
+
(entry, index) => {
|
|
411
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
412
|
+
throw new Error(
|
|
413
|
+
`provider "${providerId}" ${field}[${index}] must be { id, label, description? }`
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
const record = Object.fromEntries(
|
|
417
|
+
Object.entries(entry)
|
|
418
|
+
);
|
|
419
|
+
const id = requireNonBlankString({
|
|
420
|
+
providerId,
|
|
421
|
+
field: `${field}[${index}].id`,
|
|
422
|
+
value: record.id
|
|
423
|
+
});
|
|
424
|
+
if (seen.has(id)) {
|
|
425
|
+
throw new Error(
|
|
426
|
+
`provider "${providerId}" ${field} id ${JSON.stringify(id)} is duplicated`
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
seen.add(id);
|
|
430
|
+
const label = requireNonBlankString({
|
|
431
|
+
providerId,
|
|
432
|
+
field: `${field}[${index}].label`,
|
|
433
|
+
value: record.label
|
|
434
|
+
});
|
|
435
|
+
const description = record.description === void 0 ? void 0 : requireNonBlankString({
|
|
436
|
+
providerId,
|
|
437
|
+
field: `${field}[${index}].description`,
|
|
438
|
+
value: record.description
|
|
439
|
+
});
|
|
440
|
+
return Object.freeze({
|
|
441
|
+
id,
|
|
442
|
+
label,
|
|
443
|
+
...description === void 0 ? {} : { description }
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
);
|
|
447
|
+
return Object.freeze(normalized);
|
|
448
|
+
}
|
|
449
|
+
function validateProviderExtensionKinds(providerId, value) {
|
|
450
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
451
|
+
throw new Error(
|
|
452
|
+
`provider "${providerId}" experimental_extensionKinds must be an object keyed by kind name`
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
const entries = Object.entries(value);
|
|
456
|
+
if (entries.length > PROVIDER_EXTENSION_KINDS_MAX) {
|
|
457
|
+
throw new Error(
|
|
458
|
+
`provider "${providerId}" experimental_extensionKinds declares more than ${PROVIDER_EXTENSION_KINDS_MAX} kinds`
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
const normalized = {};
|
|
462
|
+
for (const [name, declaration] of entries) {
|
|
463
|
+
if (!PROVIDER_EXTENSION_KIND_NAME_PATTERN.test(name)) {
|
|
464
|
+
throw new Error(
|
|
465
|
+
`provider "${providerId}" experimental_extensionKinds name ${JSON.stringify(name)} must match ${PROVIDER_EXTENSION_KIND_NAME_PATTERN}`
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
if (typeof declaration !== "object" || declaration === null || Array.isArray(declaration)) {
|
|
469
|
+
throw new Error(
|
|
470
|
+
`provider "${providerId}" experimental_extensionKinds.${name} must be { item?, state? }`
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
const item = Reflect.get(declaration, "item");
|
|
474
|
+
const state = Reflect.get(declaration, "state");
|
|
475
|
+
if (item === void 0 && state === void 0) {
|
|
476
|
+
throw new Error(
|
|
477
|
+
`provider "${providerId}" experimental_extensionKinds.${name} must declare an item schema, a state schema, or both`
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
if (item !== void 0 && !isStandardSchema(item)) {
|
|
481
|
+
throw new Error(
|
|
482
|
+
`provider "${providerId}" experimental_extensionKinds.${name}.item must be a Standard Schema v1 validator`
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
if (state !== void 0 && !isStandardSchema(state)) {
|
|
486
|
+
throw new Error(
|
|
487
|
+
`provider "${providerId}" experimental_extensionKinds.${name}.state must be a Standard Schema v1 validator`
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
normalized[name] = Object.freeze({
|
|
491
|
+
...item === void 0 ? {} : { item },
|
|
492
|
+
...state === void 0 ? {} : { state }
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
return Object.freeze(normalized);
|
|
496
|
+
}
|
|
497
|
+
var PROVIDER_FALLBACK_MODELS_MAX = 64;
|
|
498
|
+
var PROVIDER_ENV_PASSTHROUGH_MAX = 32;
|
|
499
|
+
var PROVIDER_ENV_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/u;
|
|
500
|
+
function validateProviderEnvPassthrough(providerId, value) {
|
|
501
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
502
|
+
throw new Error(
|
|
503
|
+
`provider "${providerId}" experimental_env must be { passthrough: [...] }`
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
const passthrough = Reflect.get(value, "passthrough");
|
|
507
|
+
if (!Array.isArray(passthrough)) {
|
|
508
|
+
throw new Error(
|
|
509
|
+
`provider "${providerId}" experimental_env.passthrough must be an array of variable names`
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
if (passthrough.length > PROVIDER_ENV_PASSTHROUGH_MAX) {
|
|
513
|
+
throw new Error(
|
|
514
|
+
`provider "${providerId}" experimental_env.passthrough names more than ${PROVIDER_ENV_PASSTHROUGH_MAX} variables`
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
const seen = /* @__PURE__ */ new Set();
|
|
518
|
+
for (const name of passthrough) {
|
|
519
|
+
if (typeof name !== "string" || !PROVIDER_ENV_NAME_PATTERN.test(name)) {
|
|
520
|
+
throw new Error(
|
|
521
|
+
`provider "${providerId}" experimental_env.passthrough entries must match ${PROVIDER_ENV_NAME_PATTERN}`
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
if (seen.has(name)) {
|
|
525
|
+
throw new Error(
|
|
526
|
+
`provider "${providerId}" experimental_env.passthrough repeats ${JSON.stringify(name)}`
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
seen.add(name);
|
|
530
|
+
}
|
|
531
|
+
return Object.freeze([...seen]);
|
|
532
|
+
}
|
|
533
|
+
function validateProviderFallbackModels(providerId, value) {
|
|
534
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
535
|
+
throw new Error(
|
|
536
|
+
`provider "${providerId}" experimental_models must be { fallback: [...] }`
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
const fallback = Reflect.get(value, "fallback");
|
|
540
|
+
if (!Array.isArray(fallback)) {
|
|
541
|
+
throw new Error(
|
|
542
|
+
`provider "${providerId}" experimental_models.fallback must be an array`
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
if (fallback.length > PROVIDER_FALLBACK_MODELS_MAX) {
|
|
546
|
+
throw new Error(
|
|
547
|
+
`provider "${providerId}" experimental_models.fallback lists more than ${PROVIDER_FALLBACK_MODELS_MAX} models`
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
const seen = /* @__PURE__ */ new Set();
|
|
551
|
+
let defaults = 0;
|
|
552
|
+
const normalized = fallback.map((entry, index) => {
|
|
553
|
+
const field = `experimental_models.fallback[${index}]`;
|
|
554
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
555
|
+
throw new Error(`provider "${providerId}" ${field} must be an object`);
|
|
556
|
+
}
|
|
557
|
+
const record = Object.fromEntries(
|
|
558
|
+
Object.entries(entry)
|
|
559
|
+
);
|
|
560
|
+
const id = requireNonBlankString({
|
|
561
|
+
providerId,
|
|
562
|
+
field: `${field}.id`,
|
|
563
|
+
value: record.id
|
|
564
|
+
});
|
|
565
|
+
if (seen.has(id)) {
|
|
566
|
+
throw new Error(
|
|
567
|
+
`provider "${providerId}" experimental_models.fallback id ${JSON.stringify(id)} is duplicated`
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
seen.add(id);
|
|
571
|
+
const displayName = requireNonBlankString({
|
|
572
|
+
providerId,
|
|
573
|
+
field: `${field}.displayName`,
|
|
574
|
+
value: record.displayName
|
|
575
|
+
});
|
|
576
|
+
const description = requireNonBlankString({
|
|
577
|
+
providerId,
|
|
578
|
+
field: `${field}.description`,
|
|
579
|
+
value: record.description
|
|
580
|
+
});
|
|
581
|
+
const efforts = record.supportedReasoningEfforts;
|
|
582
|
+
if (!Array.isArray(efforts) || efforts.length === 0) {
|
|
583
|
+
throw new Error(
|
|
584
|
+
`provider "${providerId}" ${field}.supportedReasoningEfforts must be a non-empty array`
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
const levels = /* @__PURE__ */ new Set();
|
|
588
|
+
const supportedReasoningEfforts = efforts.map(
|
|
589
|
+
(effort, effortIndex) => {
|
|
590
|
+
if (typeof effort !== "object" || effort === null || Array.isArray(effort)) {
|
|
591
|
+
throw new Error(
|
|
592
|
+
`provider "${providerId}" ${field}.supportedReasoningEfforts[${effortIndex}] must be { reasoningEffort, description }`
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
const reasoningEffort = Reflect.get(effort, "reasoningEffort");
|
|
596
|
+
if (typeof reasoningEffort !== "string" || !PLUGIN_PROVIDER_REASONING_LEVEL_VALUES.includes(
|
|
597
|
+
reasoningEffort
|
|
598
|
+
)) {
|
|
599
|
+
throw new Error(
|
|
600
|
+
`provider "${providerId}" ${field}.supportedReasoningEfforts[${effortIndex}].reasoningEffort must be one of ${PLUGIN_PROVIDER_REASONING_LEVEL_VALUES.join(", ")}`
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
const level = reasoningEffort;
|
|
604
|
+
if (levels.has(level)) {
|
|
605
|
+
throw new Error(
|
|
606
|
+
`provider "${providerId}" ${field}.supportedReasoningEfforts repeats ${JSON.stringify(level)}`
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
levels.add(level);
|
|
610
|
+
return Object.freeze({
|
|
611
|
+
reasoningEffort: level,
|
|
612
|
+
description: requireNonBlankString({
|
|
613
|
+
providerId,
|
|
614
|
+
field: `${field}.supportedReasoningEfforts[${effortIndex}].description`,
|
|
615
|
+
value: Reflect.get(effort, "description")
|
|
616
|
+
})
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
);
|
|
620
|
+
const defaultReasoningEffort = record.defaultReasoningEffort;
|
|
621
|
+
if (typeof defaultReasoningEffort !== "string" || !levels.has(defaultReasoningEffort)) {
|
|
622
|
+
throw new Error(
|
|
623
|
+
`provider "${providerId}" ${field}.defaultReasoningEffort must be one of its supportedReasoningEfforts`
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
if (typeof record.isDefault !== "boolean") {
|
|
627
|
+
throw new Error(
|
|
628
|
+
`provider "${providerId}" ${field}.isDefault must be a boolean`
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
if (record.isDefault) defaults += 1;
|
|
632
|
+
return Object.freeze({
|
|
633
|
+
id,
|
|
634
|
+
displayName,
|
|
635
|
+
description,
|
|
636
|
+
supportedReasoningEfforts: Object.freeze(supportedReasoningEfforts),
|
|
637
|
+
defaultReasoningEffort,
|
|
638
|
+
isDefault: record.isDefault
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
if (normalized.length > 0 && defaults !== 1) {
|
|
642
|
+
throw new Error(
|
|
643
|
+
`provider "${providerId}" experimental_models.fallback must mark exactly one model isDefault (found ${defaults})`
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
return Object.freeze(normalized);
|
|
647
|
+
}
|
|
335
648
|
function validatePluginProviderDeclaration(declaration) {
|
|
336
649
|
if (typeof declaration !== "object" || declaration === null) {
|
|
337
650
|
throw new Error("provider declaration must be an object");
|
|
@@ -342,6 +655,12 @@ function validatePluginProviderDeclaration(declaration) {
|
|
|
342
655
|
`invalid provider id ${JSON.stringify(id)} \u2014 use 2-64 lowercase letters, digits, and "-", starting with a letter or digit`
|
|
343
656
|
);
|
|
344
657
|
}
|
|
658
|
+
const family = declaration.experimental_family;
|
|
659
|
+
if (family !== void 0 && (typeof family !== "string" || !PROVIDER_ID_PATTERN.test(family))) {
|
|
660
|
+
throw new Error(
|
|
661
|
+
`provider "${id}" experimental_family must use the provider id grammar (2-64 lowercase letters, digits, and "-")`
|
|
662
|
+
);
|
|
663
|
+
}
|
|
345
664
|
const displayName = typeof declaration.displayName === "string" ? declaration.displayName.trim() : "";
|
|
346
665
|
if (displayName.length === 0 || displayName.length > PLUGIN_PROVIDER_DISPLAY_NAME_MAX_CHARS) {
|
|
347
666
|
throw new Error(
|
|
@@ -392,8 +711,7 @@ function validatePluginProviderDeclaration(declaration) {
|
|
|
392
711
|
"supportsNativeUserQuestion",
|
|
393
712
|
"supportsManualCompaction",
|
|
394
713
|
"supportsThreadArchive",
|
|
395
|
-
"supportsThreadRename"
|
|
396
|
-
"supportsWorkflows"
|
|
714
|
+
"supportsThreadRename"
|
|
397
715
|
];
|
|
398
716
|
for (const field of booleanCapabilityFields) {
|
|
399
717
|
if (typeof capabilities[field] !== "boolean") {
|
|
@@ -417,7 +735,6 @@ function validatePluginProviderDeclaration(declaration) {
|
|
|
417
735
|
supportsManualCompaction: capabilities.supportsManualCompaction,
|
|
418
736
|
supportsThreadArchive: capabilities.supportsThreadArchive,
|
|
419
737
|
supportsThreadRename: capabilities.supportsThreadRename,
|
|
420
|
-
supportsWorkflows: capabilities.supportsWorkflows,
|
|
421
738
|
permissionModes: validateProviderLiteralArray({
|
|
422
739
|
providerId: id,
|
|
423
740
|
field: "capabilities.permissionModes",
|
|
@@ -455,14 +772,45 @@ function validatePluginProviderDeclaration(declaration) {
|
|
|
455
772
|
`provider "${id}" experimental_visibility "installed" requires experimental_providerHealth`
|
|
456
773
|
);
|
|
457
774
|
}
|
|
775
|
+
const strings = declaration.experimental_strings === void 0 ? void 0 : validateProviderStrings(id, declaration.experimental_strings);
|
|
776
|
+
const serviceTiers = declaration.experimental_serviceTiers === void 0 ? void 0 : validateProviderOptionDescriptors({
|
|
777
|
+
providerId: id,
|
|
778
|
+
field: "experimental_serviceTiers",
|
|
779
|
+
value: declaration.experimental_serviceTiers
|
|
780
|
+
});
|
|
781
|
+
const reasoningLevels = declaration.experimental_reasoningLevels === void 0 ? void 0 : validateProviderOptionDescriptors({
|
|
782
|
+
providerId: id,
|
|
783
|
+
field: "experimental_reasoningLevels",
|
|
784
|
+
value: declaration.experimental_reasoningLevels
|
|
785
|
+
});
|
|
786
|
+
const extensionKinds = declaration.experimental_extensionKinds === void 0 ? void 0 : validateProviderExtensionKinds(
|
|
787
|
+
id,
|
|
788
|
+
declaration.experimental_extensionKinds
|
|
789
|
+
);
|
|
790
|
+
const fallbackModels = declaration.experimental_models === void 0 ? void 0 : validateProviderFallbackModels(id, declaration.experimental_models);
|
|
791
|
+
const envPassthrough = declaration.experimental_env === void 0 ? void 0 : validateProviderEnvPassthrough(id, declaration.experimental_env);
|
|
792
|
+
const deriveProviderOptions = declaration.experimental_deriveProviderOptions;
|
|
793
|
+
if (deriveProviderOptions !== void 0 && typeof deriveProviderOptions !== "function") {
|
|
794
|
+
throw new Error(
|
|
795
|
+
`provider "${id}" experimental_deriveProviderOptions must be a function (context) => providerOptions`
|
|
796
|
+
);
|
|
797
|
+
}
|
|
458
798
|
return Object.freeze({
|
|
459
799
|
id,
|
|
460
800
|
displayName,
|
|
801
|
+
...family === void 0 ? {} : { experimental_family: family },
|
|
461
802
|
...icon === void 0 ? {} : { icon },
|
|
462
803
|
...bridgeOptions === void 0 ? {} : { experimental_bridgeOptions: bridgeOptions },
|
|
463
804
|
experimental_visibility: visibility,
|
|
464
805
|
capabilities: normalizedCapabilities,
|
|
465
|
-
composerActions
|
|
806
|
+
composerActions,
|
|
807
|
+
...strings === void 0 ? {} : { experimental_strings: strings },
|
|
808
|
+
...serviceTiers === void 0 ? {} : { experimental_serviceTiers: serviceTiers },
|
|
809
|
+
...reasoningLevels === void 0 ? {} : { experimental_reasoningLevels: reasoningLevels },
|
|
810
|
+
...extensionKinds === void 0 ? {} : { experimental_extensionKinds: extensionKinds },
|
|
811
|
+
...fallbackModels === void 0 ? {} : { experimental_models: Object.freeze({ fallback: fallbackModels }) },
|
|
812
|
+
...envPassthrough === void 0 ? {} : { experimental_env: Object.freeze({ passthrough: envPassthrough }) },
|
|
813
|
+
...deriveProviderOptions === void 0 ? {} : { experimental_deriveProviderOptions: deriveProviderOptions }
|
|
466
814
|
});
|
|
467
815
|
}
|
|
468
816
|
function isStandardSchema(value) {
|
|
@@ -1402,6 +1750,25 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
1402
1750
|
const providerRegistrations = [];
|
|
1403
1751
|
let agentConfigurationProvider = null;
|
|
1404
1752
|
let instructionProvider = null;
|
|
1753
|
+
function registerProviderDeclaration(declaration) {
|
|
1754
|
+
assertLive();
|
|
1755
|
+
const normalized = validatePluginProviderDeclaration(declaration);
|
|
1756
|
+
if (providerRegistrations.some((existing) => existing.id === normalized.id)) {
|
|
1757
|
+
throw new Error(
|
|
1758
|
+
`Provider "${normalized.id}" is already registered; a plugin cannot shadow an existing provider.`
|
|
1759
|
+
);
|
|
1760
|
+
}
|
|
1761
|
+
providerRegistrations.push(normalized);
|
|
1762
|
+
let disposed2 = false;
|
|
1763
|
+
const dispose = () => {
|
|
1764
|
+
if (disposed2) return;
|
|
1765
|
+
disposed2 = true;
|
|
1766
|
+
const index = providerRegistrations.indexOf(normalized);
|
|
1767
|
+
if (index !== -1) providerRegistrations.splice(index, 1);
|
|
1768
|
+
};
|
|
1769
|
+
disposeHooks.push(dispose);
|
|
1770
|
+
return { dispose };
|
|
1771
|
+
}
|
|
1405
1772
|
const agents = {
|
|
1406
1773
|
configure(provider) {
|
|
1407
1774
|
assertLive();
|
|
@@ -1428,23 +1795,7 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
1428
1795
|
instructionProvider = provider;
|
|
1429
1796
|
},
|
|
1430
1797
|
experimental_registerProvider(declaration) {
|
|
1431
|
-
|
|
1432
|
-
const normalized = validatePluginProviderDeclaration(declaration);
|
|
1433
|
-
if (providerRegistrations.some((existing) => existing.id === normalized.id)) {
|
|
1434
|
-
throw new Error(
|
|
1435
|
-
`Provider "${normalized.id}" is already registered; a plugin cannot shadow an existing provider.`
|
|
1436
|
-
);
|
|
1437
|
-
}
|
|
1438
|
-
providerRegistrations.push(normalized);
|
|
1439
|
-
let disposed2 = false;
|
|
1440
|
-
const dispose = () => {
|
|
1441
|
-
if (disposed2) return;
|
|
1442
|
-
disposed2 = true;
|
|
1443
|
-
const index = providerRegistrations.indexOf(normalized);
|
|
1444
|
-
if (index !== -1) providerRegistrations.splice(index, 1);
|
|
1445
|
-
};
|
|
1446
|
-
disposeHooks.push(dispose);
|
|
1447
|
-
return { dispose };
|
|
1798
|
+
return registerProviderDeclaration(declaration);
|
|
1448
1799
|
},
|
|
1449
1800
|
registerTool(tool) {
|
|
1450
1801
|
assertLive();
|
|
@@ -1815,6 +2166,11 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
1815
2166
|
handlers.push(handler);
|
|
1816
2167
|
}
|
|
1817
2168
|
};
|
|
2169
|
+
const providers = {
|
|
2170
|
+
register(declaration) {
|
|
2171
|
+
return registerProviderDeclaration(declaration);
|
|
2172
|
+
}
|
|
2173
|
+
};
|
|
1818
2174
|
const bb = {
|
|
1819
2175
|
pluginId,
|
|
1820
2176
|
log,
|
|
@@ -1826,6 +2182,7 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
1826
2182
|
background,
|
|
1827
2183
|
cli,
|
|
1828
2184
|
agents,
|
|
2185
|
+
providers,
|
|
1829
2186
|
ui,
|
|
1830
2187
|
events,
|
|
1831
2188
|
status,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@get-bb/plugin-sdk",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.12",
|
|
4
4
|
"homepage": "https://github.com/get-bb/bb#readme",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/get-bb/bb/issues"
|
|
@@ -32,6 +32,12 @@
|
|
|
32
32
|
"import": "./dist/provider-bridge.js",
|
|
33
33
|
"default": "./dist/provider-bridge.js"
|
|
34
34
|
},
|
|
35
|
+
"./provider-bridge/testing": {
|
|
36
|
+
"source": "./src/provider-bridge-testing.ts",
|
|
37
|
+
"types": "./bundled-types/bb-plugin-sdk-provider-bridge-testing.d.ts",
|
|
38
|
+
"import": "./dist/provider-bridge-testing.js",
|
|
39
|
+
"default": "./dist/provider-bridge-testing.js"
|
|
40
|
+
},
|
|
35
41
|
"./app": {
|
|
36
42
|
"source": "./src/app.ts",
|
|
37
43
|
"types": "./bundled-types/bb-plugin-sdk-app.d.ts",
|