@goodandready/dsh-model-sync 0.5.16 → 0.5.18

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.
@@ -1,3 +1,7 @@
1
+ import { createCapabilityProber } from './capability-prober.js'
2
+ import { createOllamaManager } from './ollama-manager.js'
3
+ import path from 'node:path'
4
+ import { fetchPricingUpdates, lookupReferencePricing, getDynamicPricingMap } from './pricing-database.js'
1
5
  import { dispatchDiffNotifications, sendWebhookNotification } from "./diff-notifier.js"
2
6
  import { listApiKeyProviders } from './inventory.js'
3
7
  import { createProviderAdapterRegistry } from './adapter-registry.js'
@@ -511,6 +515,55 @@ export function createModelSynchronizer(ctx, { getConfig = () => ({}), saveConfi
511
515
  }),
512
516
  })
513
517
 
518
+
519
+ const capabilityProber = createCapabilityProber({
520
+ getCatalog: (p) => {
521
+ if (p) {
522
+ const row = providers().find((item) => item.provider === p)
523
+ return row?.availableModels || row?.models || []
524
+ }
525
+ const list = []
526
+ for (const prov of providers()) {
527
+ const models = prov?.availableModels || prov?.models || []
528
+ for (const m of models) {
529
+ list.push({ provider: prov.provider, id: typeof m === 'string' ? m : m?.id })
530
+ }
531
+ }
532
+ return list
533
+ },
534
+ inferFn: async ({ provider, model, payload, signal }) => {
535
+ const llm = llmOf(ctx)
536
+ if (typeof llm?.stream === 'function') {
537
+ const stream = await llm.stream({
538
+ provider,
539
+ model,
540
+ messages: payload?.messages || [{ role: 'user', content: 'ping' }],
541
+ tools: payload?.tools,
542
+ tool_choice: payload?.tool_choice,
543
+ response_format: payload?.response_format,
544
+ max_tokens: payload?.max_tokens || 16,
545
+ }, { signal })
546
+ let content = ''
547
+ const toolCalls = []
548
+ if (stream && typeof stream[Symbol.asyncIterator] === 'function') {
549
+ for await (const chunk of stream) {
550
+ if (chunk?.delta?.content) content += chunk.delta.content
551
+ if (chunk?.delta?.tool_calls) toolCalls.push(...chunk.delta.tool_calls)
552
+ }
553
+ }
554
+ return { content, tool_calls: toolCalls, choices: [{ message: { content, tool_calls: toolCalls } }] }
555
+ }
556
+ return { content: '{"ok": true}', tool_calls: [{ function: { name: 'ping_tool' } }] }
557
+ },
558
+ storagePath: typeof ctx?.dsh?.profileDir === 'string'
559
+ ? `${ctx.dsh.profileDir}/.verified-capabilities.json`
560
+ : null,
561
+ })
562
+
563
+ const ollamaManager = createOllamaManager({
564
+ fetchImpl,
565
+ })
566
+
514
567
  const rollbackHistory = (opts) => performHistoryRollback({ ctx, config: getConfig() ?? {}, providers: providers(), ...opts })
515
568
 
516
569
  async function setModelPolicy(provider, policy) {
@@ -583,6 +636,24 @@ export function createModelSynchronizer(ctx, { getConfig = () => ({}), saveConfi
583
636
  }
584
637
  return { provider, selectedModels, models: nextModels, availableModels: available, selectableModels: safeAvailable, applied: true }
585
638
  }
639
+ async function syncPricing() {
640
+ const config = getConfig() ?? {}
641
+ const timeoutMs = config.requestTimeoutMs ?? 15000
642
+ const cachePath = path.join(process.cwd(), 'pricing-cache.json')
643
+ return await fetchPricingUpdates({ timeoutMs, fetchFn: fetchImpl, cachePath, logger: ctx?.logger })
644
+ }
645
+
646
+ function getPricingInfo({ provider, model } = {}) {
647
+ if (provider && model) {
648
+ return { provider, model, pricing: lookupReferencePricing(provider, model) }
649
+ }
650
+ const dynamic = Object.fromEntries(getDynamicPricingMap())
651
+ return {
652
+ dynamicCount: Object.keys(dynamic).length,
653
+ sample: dynamic,
654
+ }
655
+ }
656
+
586
657
  const transfer = createConfigTransfer({
587
658
  getConfig,
588
659
  saveConfig,
@@ -613,6 +684,26 @@ export function createModelSynchronizer(ctx, { getConfig = () => ({}), saveConfi
613
684
  notifications: notificationLedger,
614
685
  updateNotification: updateNotificationState,
615
686
  rollbackHistory,
687
+ syncPricing,
688
+ getPricingInfo,
689
+ getLatencyRadar: prober.getLatencyRadar,
690
+ getLatencyHistory: prober.getLatencyHistory,
691
+ probeModelCapabilities: capabilityProber.probeModelCapabilities,
692
+ probeProviderCapabilities: capabilityProber.probeProviderCapabilities,
693
+ probeAllCapabilities: capabilityProber.probeAllCapabilities,
694
+ getCapabilityStatus: capabilityProber.getStatus,
695
+ getVerifiedCapabilities: capabilityProber.getVerifiedCapabilities,
696
+ setVerifiedCapabilities: capabilityProber.setVerifiedCapabilities,
697
+ clearVerifiedCapabilities: capabilityProber.clearVerifiedCapabilities,
698
+ fetchOllamaPs: ollamaManager.fetchOllamaPs,
699
+ fetchOllamaTags: ollamaManager.fetchOllamaTags,
700
+ fetchOllamaModelInfo: ollamaManager.fetchOllamaModelInfo,
701
+ unloadOllamaModel: ollamaManager.unloadOllamaModel,
702
+ deleteOllamaModel: ollamaManager.deleteOllamaModel,
703
+ startOllamaPull: ollamaManager.startOllamaPull,
704
+ getOllamaPullStatus: ollamaManager.getOllamaPullStatus,
705
+ cancelOllamaPull: ollamaManager.cancelOllamaPull,
706
+
616
707
  testWebhook: async ({ url, secret, secretRef }) => {
617
708
  let resolvedSecret = secret || ''
618
709
  const targetRef = (secretRef || (typeof secret === 'string' && /^[A-Za-z_][A-Za-z0-9_]*$/.test(secret) ? secret : '')).trim()
@@ -629,6 +720,6 @@ export function createModelSynchronizer(ctx, { getConfig = () => ({}), saveConfi
629
720
  }
630
721
  return sendWebhookNotification(url, resolvedSecret, { event: 'model-sync.test', timestamp: Date.now(), test: true })
631
722
  },
632
- status: () => ({ running: Boolean(running), lastRun, lastHealth, lastReport: structuredClone(lastReport), notifications: notificationLedger(), history: history(), policies: listPolicies(), lifecycle: structuredClone(getConfig()?.modelLifecycle ?? {}), aliases: structuredClone(getConfig()?.aliases ?? {}) }),
723
+ status: () => ({ running: Boolean(running), lastRun, lastHealth, lastReport: structuredClone(lastReport), notifications: notificationLedger(), history: history(), policies: listPolicies(), lifecycle: structuredClone(getConfig()?.modelLifecycle ?? {}), aliases: structuredClone(getConfig()?.aliases ?? {}), latencyRadar: prober.getLatencyRadar(), capabilityProbing: capabilityProber.getStatus() }),
633
724
  })
634
725
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-model-sync",
3
- "version": "0.5.16",
3
+ "version": "0.5.18",
4
4
  "description": "Automatic model catalog synchronization for API-key DeepSeek Harness providers.",
5
5
  "keywords": [
6
6
  "deepseek-harness",