Insurgently

Obsidian plugin· Active · beta · not yet released

Model Hub

Named roles mapped to provider and model, keys kept in secret storage, and a cost ledger with the billed cost of every call. Other plugins call it for their AI.

Beta. Model Hub is not released yet. These pages describe the build in progress.

Add Model Hub to your plugin

Find the Hub, register your roles and make a first call, in about twenty lines.

With Model Hub, your plugin holds no keys and names no models. It declares the jobs it needs a model for, and the user decides which models serve them. Spend is credited to your plugin in the user's ledger.

Before you start

  • Model Hub is desktop only, so a plugin that requires it is too.
  • The API's types aren't published as a package yet. Until they are, copy model-hub-api.d.ts into your plugin: it is every public declaration in one file. getHub and onHubReady are a few lines each; copy them from api/index.ts.

Steps

  1. Find the Hub. getHub checks that Model Hub is installed and that its API is new enough for you. If not, it gives a plain message to show the user.

    const found = getHub(this.app, '0.4.0');
    if (!found.hub) return new Notice(found.message);
    const hub = found.hub;
    
  2. Register your roles. A role is named namespace.name in lowercase. The first plugin to use a namespace owns it. Each role names a tier (balanced if you name none).

    hub.registerRoles(this.manifest.id, [
      { name: 'mine.summarize', description: 'Summaries of a note', tier: 'quick' },
      { name: 'mine.embed', description: 'Vectors for search', tier: 'embedding' },
    ]);
    
  3. Make a call. Pass for so the ledger says what the call was about.

    const r = await hub.complete('mine.summarize', [{ role: 'user', content: noteText }], { for: file.path });
    // r.text, r.usage, r.listedUsd, r.billedUsd, r.servedModel, r.fellBack …
    
  4. Handle refusals. Every refusal or failure is an error with a code and a message written for the user.

    try {
      await hub.complete('mine.summarize', messages);
    } catch (e) {
      new Notice((e as Error).message); // e.code: 'over-ceiling', 'over-budget', 'provider-unavailable' …
    }
    
  5. Let the user remap your roles. One call opens the Hub's role editor for your plugin, so you have no model settings to build.

    hub.openRoleEditor(this.manifest.id);
    

If the Hub is reloaded

The user may disable and enable Model Hub while your plugin runs. The new Hub fires model-hub:ready on the workspace. onHubReady runs your callback now and on every reload, so do your registration inside it:

onHubReady(this.app, this, '0.4.0', (hub) => {
  hub.registerRoles(this.manifest.id, MY_ROLES);
  hub.registerSkills(this.manifest.id, MY_SKILLS);
});

Registering roles again is harmless. Registered skills are lost on a reload, so they must be registered again.

What you get

  • Your roles show in Settings → Model Hub → Roles under your plugin's name.
  • Every call is checked against the user's limits before it is sent, and recorded in the ledger with its cost.
  • When a model fails, the Hub falls back along the user's own list and tells you (fellBack, attempts).

Related