@elisym/cli 0.21.1 → 0.21.3

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/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { ReadableStream } from 'node:stream/web';
3
3
  import { readFileSync, existsSync, readdirSync, statSync, renameSync, chmodSync, mkdirSync, writeFileSync } from 'node:fs';
4
4
  import { dirname, join, resolve, basename, relative, sep } from 'node:path';
5
- import { SolanaPaymentStrategy, validateAgentName, RELAYS, ElisymIdentity, formatSol, formatAssetAmount, USDC_SOLANA_DEVNET, ElisymClient, MediaService, POLICY_D_TAG_PREFIX, KIND_LONG_FORM_ARTICLE, POLICY_T_TAG, jobRequestKind, DEFAULT_KIND_OFFSET, toDTag, DEFAULTS, makeCensor, DEFAULT_REDACT_PATHS, createSlidingWindowLimiter, getProtocolProgramId, getProtocolConfig, utf8ByteLength, LIMITS, calculateProtocolFee, decodeJobPayload, BoundedSet, KIND_JOB_FEEDBACK, NATIVE_SOL } from '@elisym/sdk';
5
+ import { SolanaPaymentStrategy, validateAgentName, RELAYS, ElisymIdentity, formatSol, formatAssetAmount, USDC_SOLANA_DEVNET, ElisymClient, MediaService, POLICY_D_TAG_PREFIX, KIND_LONG_FORM_ARTICLE, jobRequestKind, DEFAULT_KIND_OFFSET, toDTag, DEFAULTS, makeCensor, DEFAULT_REDACT_PATHS, POLICY_T_TAG, createSlidingWindowLimiter, getProtocolProgramId, getProtocolConfig, utf8ByteLength, LIMITS, calculateProtocolFee, decodeJobPayload, BoundedSet, KIND_JOB_FEEDBACK, NATIVE_SOL } from '@elisym/sdk';
6
6
  import { ElisymYamlSchema, resolveInHome, resolveInProject, createAgentDir, writeYamlInitial, writeExampleSkillTemplate, writeSecrets, listAgents, loadAgent, writeYaml, agentPaths, readMediaCache, loadPoliciesFromDir, ensureGitignoreHasIrohEntry, lookupCachedUrl, newCacheEntry, writeMediaCache } from '@elisym/sdk/agent-store';
7
7
  import { isAddress, createSolanaRpc, address } from '@solana/kit';
8
8
  import { generateSecretKey, getPublicKey, nip19, verifyEvent } from 'nostr-tools';
@@ -242,6 +242,7 @@ async function verifyKeyDeep(apiKey, model, signal) {
242
242
  return {
243
243
  ok: false,
244
244
  reason: "unavailable",
245
+ status: response.status,
245
246
  error: `HTTP ${response.status}: ${body.slice(0, 200)}`
246
247
  };
247
248
  } catch (error) {
@@ -490,6 +491,7 @@ function createOpenAICompatibleProvider(config) {
490
491
  return {
491
492
  ok: false,
492
493
  reason: "unavailable",
494
+ status: response.status,
493
495
  error: `HTTP ${response.status}: ${body.slice(0, 200)}`
494
496
  };
495
497
  } catch (error) {
@@ -790,6 +792,7 @@ async function verifyKeyDeep2(apiKey, model, signal) {
790
792
  return {
791
793
  ok: false,
792
794
  reason: "unavailable",
795
+ status: response.status,
793
796
  error: `HTTP ${response.status}: ${body.slice(0, 200)}`
794
797
  };
795
798
  } catch (error) {
@@ -3974,6 +3977,7 @@ async function cmdStart(nameArg, options = {}) {
3974
3977
  (skill) => skill.mode !== "llm" && skill.llmOverride?.provider && skill.llmOverride?.model
3975
3978
  );
3976
3979
  const monitorPairs = /* @__PURE__ */ new Map();
3980
+ const retiredModels = /* @__PURE__ */ new Set();
3977
3981
  const triplesByKey = /* @__PURE__ */ new Map();
3978
3982
  const dependentSkillsByProvider = /* @__PURE__ */ new Map();
3979
3983
  let agentDefaultCacheKey;
@@ -4070,7 +4074,10 @@ async function cmdStart(nameArg, options = {}) {
4070
4074
  model: pair.model,
4071
4075
  verifyFn
4072
4076
  });
4073
- healthMonitor.seed(pair.provider, pair.model, verification);
4077
+ const modelRetired = !verification.ok && verification.reason === "unavailable" && verification.status === 404;
4078
+ if (!modelRetired) {
4079
+ healthMonitor.seed(pair.provider, pair.model, verification);
4080
+ }
4074
4081
  if (verification.ok) {
4075
4082
  console.log("ok");
4076
4083
  } else if (verification.reason === "invalid") {
@@ -4092,6 +4099,13 @@ async function cmdStart(nameArg, options = {}) {
4092
4099
  `
4093
4100
  );
4094
4101
  process.exit(1);
4102
+ } else if (verification.status === 404) {
4103
+ console.log("retired");
4104
+ console.error(
4105
+ ` ! ${pair.provider} model "${pair.model}" no longer exists (HTTP 404). Update its model: in the SKILL.md / elisym.yaml. Skills using it will not be advertised.
4106
+ `
4107
+ );
4108
+ retiredModels.add(`${pair.provider}::${pair.model}`);
4095
4109
  } else {
4096
4110
  console.log("unavailable");
4097
4111
  console.warn(
@@ -4210,7 +4224,36 @@ async function cmdStart(nameArg, options = {}) {
4210
4224
  const localPolicyDTags = new Set(
4211
4225
  policies.map((policy) => `${POLICY_D_TAG_PREFIX}${policy.type}`)
4212
4226
  );
4227
+ async function fetchPublishedPolicies() {
4228
+ try {
4229
+ return await client.pool.querySync({
4230
+ kinds: [KIND_LONG_FORM_ARTICLE],
4231
+ authors: [identity.publicKey],
4232
+ "#t": [POLICY_T_TAG]
4233
+ });
4234
+ } catch {
4235
+ return [];
4236
+ }
4237
+ }
4238
+ const publishedPolicies = await fetchPublishedPolicies();
4239
+ const latestPolicyByDTag = /* @__PURE__ */ new Map();
4240
+ for (const event of publishedPolicies) {
4241
+ const dTag = event.tags.find((tag) => tag[0] === "d")?.[1];
4242
+ if (!dTag) {
4243
+ continue;
4244
+ }
4245
+ const prev = latestPolicyByDTag.get(dTag);
4246
+ if (!prev || event.created_at > prev.created_at) {
4247
+ latestPolicyByDTag.set(dTag, event);
4248
+ }
4249
+ }
4213
4250
  for (const policy of policies) {
4251
+ const onRelay = latestPolicyByDTag.get(`${POLICY_D_TAG_PREFIX}${policy.type}`);
4252
+ const relayVersion = onRelay?.tags.find((tag) => tag[0] === "policy_version")?.[1];
4253
+ if (onRelay && onRelay.content && relayVersion === policy.version && onRelay.content === policy.content) {
4254
+ console.log(` * Policy: ${policy.type}@${policy.version} (unchanged, skipped)`);
4255
+ continue;
4256
+ }
4214
4257
  try {
4215
4258
  const { naddr } = await client.policies.publishPolicy(identity, policy);
4216
4259
  console.log(` * Policy: ${policy.type}@${policy.version} -> ${naddr}`);
@@ -4231,31 +4274,23 @@ async function cmdStart(nameArg, options = {}) {
4231
4274
  );
4232
4275
  }
4233
4276
  }
4234
- try {
4235
- const existingPolicies = await client.pool.querySync({
4236
- kinds: [KIND_LONG_FORM_ARTICLE],
4237
- authors: [identity.publicKey],
4238
- "#t": [POLICY_T_TAG]
4239
- });
4240
- for (const event of existingPolicies) {
4241
- const dTag = event.tags.find((tag) => tag[0] === "d")?.[1];
4242
- if (!dTag || localPolicyDTags.has(dTag)) {
4243
- continue;
4244
- }
4245
- if (!event.content) {
4246
- continue;
4247
- }
4248
- const type = event.tags.find((tag) => tag[0] === "policy_type")?.[1];
4249
- if (!type) {
4250
- continue;
4251
- }
4252
- try {
4253
- await client.policies.deletePolicy(identity, type);
4254
- console.log(` Removed stale policy: ${type}`);
4255
- } catch {
4256
- }
4277
+ for (const event of publishedPolicies) {
4278
+ const dTag = event.tags.find((tag) => tag[0] === "d")?.[1];
4279
+ if (!dTag || localPolicyDTags.has(dTag)) {
4280
+ continue;
4281
+ }
4282
+ if (!event.content) {
4283
+ continue;
4284
+ }
4285
+ const type = event.tags.find((tag) => tag[0] === "policy_type")?.[1];
4286
+ if (!type) {
4287
+ continue;
4288
+ }
4289
+ try {
4290
+ await client.policies.deletePolicy(identity, type);
4291
+ console.log(` Removed stale policy: ${type}`);
4292
+ } catch {
4257
4293
  }
4258
- } catch {
4259
4294
  }
4260
4295
  const kinds = [jobRequestKind(DEFAULT_KIND_OFFSET)];
4261
4296
  function buildCard(skill) {
@@ -4282,8 +4317,26 @@ async function cmdStart(nameArg, options = {}) {
4282
4317
  } : void 0
4283
4318
  };
4284
4319
  }
4320
+ function retiredModelKeyForSkill(skill) {
4321
+ if (skill.resolvedTriple) {
4322
+ return `${skill.resolvedTriple.provider}::${skill.resolvedTriple.model}`;
4323
+ }
4324
+ if (skill.llmOverride?.provider && skill.llmOverride?.model) {
4325
+ return `${skill.llmOverride.provider}::${skill.llmOverride.model}`;
4326
+ }
4327
+ return void 0;
4328
+ }
4285
4329
  let cardsPublished = 0;
4286
4330
  for (const skill of allSkills) {
4331
+ const modelKey = retiredModelKeyForSkill(skill);
4332
+ if (modelKey && retiredModels.has(modelKey)) {
4333
+ console.warn(` ! Not advertising "${skill.name}" - its model was retired (HTTP 404).`);
4334
+ logger.warn(
4335
+ { event: "publish_skipped_retired", kind: 31990, skill: skill.name, model: modelKey },
4336
+ "capability not advertised - model retired"
4337
+ );
4338
+ continue;
4339
+ }
4287
4340
  try {
4288
4341
  await client.discovery.publishCapability(identity, buildCard(skill), kinds);
4289
4342
  cardsPublished += 1;