thinkpool-pair 0.7.280 → 0.7.281
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/bridge.mjs +12 -3
- package/package.json +1 -1
- package/providers.mjs +21 -0
- package/thinkpool-capabilities.json +3 -2
package/bridge.mjs
CHANGED
|
@@ -46,7 +46,7 @@ import { createPermNotifier, shouldNotifyTurnDone, permissionSummary, clipSummar
|
|
|
46
46
|
// resolveProviderEnv(id) → {ANTHROPIC_BASE_URL,ANTHROPIC_AUTH_TOKEN,ANTHROPIC_MODEL} for a
|
|
47
47
|
// registered custom provider, or null for the built-in/unknown (leave the default env intact).
|
|
48
48
|
// Multi-provider BYOK slice 1: a lane spawned with a `provider` id runs on that endpoint.
|
|
49
|
-
import { resolveProviderEnv, providerNameMap, publicKeyB64, announceProviders, listProviders, addProvider, removeProvider, unseal, effectiveLaneModel, sameProviderEnv, providerModel } from './providers.mjs'
|
|
49
|
+
import { resolveProviderEnv, resolveProviderRef, providerNameMap, publicKeyB64, announceProviders, listProviders, addProvider, removeProvider, unseal, effectiveLaneModel, sameProviderEnv, providerModel } from './providers.mjs'
|
|
50
50
|
import { validateProviderSwitch, providerSwitchPlan, BUILTIN_PROVIDER } from './switch-provider.mjs'
|
|
51
51
|
import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk'
|
|
52
52
|
import { z } from 'zod'
|
|
@@ -2071,6 +2071,10 @@ function openStructured({ id, runtime = 'claude', model, models, effort, resume,
|
|
|
2071
2071
|
const isIndependentMain = !entry.spawnedBy && !entry.sideParent && !entry.flowRole && (entry.spawnDepth || 0) === 0
|
|
2072
2072
|
const canOpenMainConductor = isIndependentMain && entry.cascadeRole !== 'conductor'
|
|
2073
2073
|
const canSpawnWorkers = isIndependentMain
|
|
2074
|
+
const registeredProviderChoices = () => announceProviders()
|
|
2075
|
+
.filter((provider) => provider.id !== 'anthropic')
|
|
2076
|
+
.map((provider) => `${provider.name}${provider.model ? ` (${provider.model})` : ''}`)
|
|
2077
|
+
.join(', ')
|
|
2074
2078
|
const resolveAgentOpen = (args, { worker = false } = {}) => {
|
|
2075
2079
|
const runtime = args?.runtime || entry.runtime || 'claude'
|
|
2076
2080
|
if (runtime === 'codex' && args?.provider) return { error: 'A Codex terminal uses its Codex/OpenAI login in v1; custom bridge providers are not wired to Codex yet. Omit provider or open a Claude terminal for that provider.' }
|
|
@@ -2084,6 +2088,11 @@ function openStructured({ id, runtime = 'claude', model, models, effort, resume,
|
|
|
2084
2088
|
if (runtime === 'hermes' && !modelCatalogValues(catalog).has(args.model)) {
|
|
2085
2089
|
return { error: `Could not open a Hermes worker on ${JSON.stringify(args.model)} — that exact model is not in this parent session's ACP catalog.` }
|
|
2086
2090
|
}
|
|
2091
|
+
const provider = runtime === 'claude' && args?.provider ? resolveProviderRef(args.provider) : args?.provider
|
|
2092
|
+
if (runtime === 'claude' && args?.provider && !provider) {
|
|
2093
|
+
const choices = registeredProviderChoices()
|
|
2094
|
+
return { error: `Unknown registered provider ${JSON.stringify(args.provider)}. No lane was opened and the built-in Claude login was not used.${choices ? ` Available provider names: ${choices}.` : ' No custom providers are registered on this host.'}` }
|
|
2095
|
+
}
|
|
2087
2096
|
if (runtime === 'claude' && !args?.provider && args?.model && /^gpt-/i.test(args.model)) {
|
|
2088
2097
|
return { error: `Could not open a Claude terminal on Codex model ${JSON.stringify(args.model)}. Choose runtime="codex" or a Claude model.` }
|
|
2089
2098
|
}
|
|
@@ -2096,7 +2105,7 @@ function openStructured({ id, runtime = 'claude', model, models, effort, resume,
|
|
|
2096
2105
|
// permission-card mode from the conductor and never honor a lower explicit
|
|
2097
2106
|
// override: spawn_terminal always opens them in bypassPermissions.
|
|
2098
2107
|
mode: worker ? 'bypassPermissions' : (args?.mode || (entry.mode === 'plan' ? 'default' : entry.mode)),
|
|
2099
|
-
provider
|
|
2108
|
+
provider,
|
|
2100
2109
|
}
|
|
2101
2110
|
}
|
|
2102
2111
|
const dispatchContext = (now = Date.now()) => ({
|
|
@@ -2414,7 +2423,7 @@ function openStructured({ id, runtime = 'claude', model, models, effort, resume,
|
|
|
2414
2423
|
model: z.string().optional().describe('model for the chosen runtime; Hermes workers require an exact ACP catalog ID such as nous:anthropic/claude-sonnet-4.6'),
|
|
2415
2424
|
sliceType: z.enum(['scaffold', 'feature', 'fix', 'review']).optional().describe('optional cascade slice tier; omitted preserves normal inheritance/default, explicit model wins'),
|
|
2416
2425
|
runtime: z.enum(['claude', 'codex', 'hermes']).optional().describe('agent runtime for the new lane; Hermes is allowed only from a top-level Hermes parent with an explicit catalog model'),
|
|
2417
|
-
provider: z.string().optional().describe(
|
|
2426
|
+
provider: z.string().optional().describe(`optional registered Claude-compatible provider name or id; omit for built-in Anthropic${registeredProviderChoices() ? `. Available now: ${registeredProviderChoices()}` : ''}`),
|
|
2418
2427
|
mode: z.enum(['default', 'acceptEdits', 'bypassPermissions', 'plan']).optional().describe('accepted for compatibility; spawned workers always run autonomously in bypassPermissions'),
|
|
2419
2428
|
},
|
|
2420
2429
|
async (args) => {
|
package/package.json
CHANGED
package/providers.mjs
CHANGED
|
@@ -333,6 +333,27 @@ export function announceProviders() {
|
|
|
333
333
|
return [{ id: BUILTIN_ID, name: 'Anthropic (Claude)', model: null, group: BUILTIN_ID }, ...custom]
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
+
/**
|
|
337
|
+
* Resolve an agent-facing provider reference without ever falling through to the
|
|
338
|
+
* built-in Claude login. Accept an exact id, a unique case-insensitive display
|
|
339
|
+
* name, or a unique configured model. Unknown/ambiguous references return null
|
|
340
|
+
* so callers can fail closed and show the current safe choices.
|
|
341
|
+
*/
|
|
342
|
+
export function resolveProviderRef(ref) {
|
|
343
|
+
if (!ref || ref === BUILTIN_ID) return BUILTIN_ID
|
|
344
|
+
const raw = String(ref).trim()
|
|
345
|
+
if (!raw) return BUILTIN_ID
|
|
346
|
+
const providers = loadProviders()
|
|
347
|
+
const exact = providers.find((provider) => provider.id === raw)
|
|
348
|
+
if (exact) return exact.id
|
|
349
|
+
const needle = raw.toLocaleLowerCase()
|
|
350
|
+
const matches = providers.filter((provider) => (
|
|
351
|
+
String(provider.name || '').trim().toLocaleLowerCase() === needle
|
|
352
|
+
|| String(provider.model || '').trim().toLocaleLowerCase() === needle
|
|
353
|
+
))
|
|
354
|
+
return matches.length === 1 ? matches[0].id : null
|
|
355
|
+
}
|
|
356
|
+
|
|
336
357
|
/**
|
|
337
358
|
* id → name map for the ROOM announce's per-lane provider projection (name-only,
|
|
338
359
|
* NEVER key or baseUrl). Built once per announce so a cross-device viewer resolves
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"bundleVersion":
|
|
3
|
+
"bundleVersion": 7,
|
|
4
4
|
"contracts": [
|
|
5
5
|
{
|
|
6
6
|
"id": "room-coordination",
|
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"id": "work-routing",
|
|
44
|
-
"version":
|
|
44
|
+
"version": 3,
|
|
45
|
+
"providerRoutingContract": "A Claude worker may select a connected Anthropic-compatible provider by durable id, unique display name, or unique configured model. Unknown or ambiguous references fail closed and must never fall through to built-in Claude.",
|
|
45
46
|
"routes": [
|
|
46
47
|
{
|
|
47
48
|
"id": "work-routing",
|