@elisym/sdk 0.17.0 → 0.19.0

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.d.cts CHANGED
@@ -56,6 +56,37 @@ interface PaymentInfo {
56
56
  /** Display symbol (e.g. 'SOL', 'USDC'). */
57
57
  symbol?: string;
58
58
  }
59
+ /**
60
+ * Legal/operational policy published by an agent (NIP-23 long-form article,
61
+ * kind 30023). One event per `(pubkey, type)` slot; replaceable by `d`-tag.
62
+ *
63
+ * `type` is open vocabulary - common values: `tos`, `privacy`, `refund`,
64
+ * `aup`, `sla`, `dpa`, `jurisdiction`. Validation regex `POLICY_TYPE_REGEX`.
65
+ */
66
+ interface AgentPolicy {
67
+ type: string;
68
+ version: string;
69
+ title: string;
70
+ summary?: string;
71
+ /** Full markdown body. */
72
+ content: string;
73
+ /** NIP-19 `naddr` reference, e.g. for sharing or migration to dedicated kind. */
74
+ naddr: string;
75
+ /** Underlying NIP-23 d-tag (e.g. `elisym-policy-tos`). */
76
+ dTag: string;
77
+ /** Event `created_at` in unix seconds (NIP-23 spec: defaults to publication date). */
78
+ publishedAt: number;
79
+ eventId: string;
80
+ authorPubkey: string;
81
+ }
82
+ /** Input shape for `PoliciesService.publishPolicy`. */
83
+ interface PolicyInput {
84
+ type: string;
85
+ version: string;
86
+ title: string;
87
+ summary?: string;
88
+ content: string;
89
+ }
59
90
  /** Agent discovered from the network. */
60
91
  interface Agent {
61
92
  pubkey: string;
@@ -597,6 +628,33 @@ declare class PingService {
597
628
  sendPong(identity: ElisymIdentity, recipientPubkey: string, nonce: string): Promise<void>;
598
629
  }
599
630
 
631
+ declare class PoliciesService {
632
+ private pool;
633
+ constructor(pool: NostrPool);
634
+ /**
635
+ * Fetch all elisym policies published by `pubkey`. Verifies signatures,
636
+ * dedupes by d-tag (latest `created_at` wins), and returns sorted by `type`
637
+ * for deterministic UI rendering.
638
+ *
639
+ * Returns `[]` on empty result. Network errors propagate to the caller.
640
+ */
641
+ fetchPolicies(pubkey: string): Promise<AgentPolicy[]>;
642
+ /**
643
+ * Publish a policy as a NIP-23 long-form article (kind 30023). Replaces any
644
+ * existing policy of the same `type` for this pubkey via the addressable
645
+ * `(kind, pubkey, d-tag)` slot.
646
+ */
647
+ publishPolicy(identity: ElisymIdentity, input: PolicyInput): Promise<{
648
+ eventId: string;
649
+ naddr: string;
650
+ }>;
651
+ /**
652
+ * Tombstone a policy by publishing an empty replacement under the same
653
+ * `(kind, pubkey, d-tag)` slot. Readers skip events with empty content.
654
+ */
655
+ deletePolicy(identity: ElisymIdentity, type: string): Promise<string>;
656
+ }
657
+
600
658
  interface ElisymClientFullConfig extends ElisymClientConfig {
601
659
  payment?: PaymentStrategy;
602
660
  /** Custom upload URL for file uploads (defaults to nostr.build). */
@@ -608,11 +666,50 @@ declare class ElisymClient {
608
666
  readonly marketplace: MarketplaceService;
609
667
  readonly ping: PingService;
610
668
  readonly media: MediaService;
669
+ readonly policies: PoliciesService;
611
670
  readonly payment: PaymentStrategy;
612
671
  constructor(config?: ElisymClientFullConfig);
613
672
  close(): void;
614
673
  }
615
674
 
675
+ /**
676
+ * Customer-facing error feedback that arrives via `subscribeToJobUpdates`'s
677
+ * `onError` callback can come from many places:
678
+ *
679
+ * - The runtime's stable `Agent temporarily unavailable` string when the
680
+ * LLM health gate refuses a job (preflight) or an in-flight skill
681
+ * surfaced a billing/invalid signal.
682
+ * - The runtime's `Internal processing error` sanitization mask for any
683
+ * "<Provider> API error: ..." string that leaks out of an LLM call.
684
+ * - Raw script-skill failures the runtime forwards as-is when the
685
+ * message does not contain "API" - e.g. shell scripts that reach
686
+ * Anthropic's `count_tokens` endpoint and exit 1 with the body in
687
+ * stderr instead of using the canonical exit-42 contract.
688
+ * - Generic transport errors (timeouts, "Provider returned an error",
689
+ * rate-limit refusals, payment errors).
690
+ *
691
+ * Customers don't care which path produced the error - they care whether
692
+ * the agent is down (try later, payment recoverable) or something else
693
+ * went wrong (their input, their wallet, etc). This classifier collapses
694
+ * the first three categories into a single `agent-unavailable` kind so
695
+ * the UI can render one stable message regardless of how the underlying
696
+ * provider chose to surface the failure.
697
+ *
698
+ * Markers are kept as a permissive superset of every billing/auth phrase
699
+ * the CLI and skill scripts are known to emit. Adding a new marker is
700
+ * always safe; removing one risks classifying a real outage as `unknown`.
701
+ */
702
+ type JobErrorKind = 'agent-unavailable' | 'unknown';
703
+ /**
704
+ * Classify a customer-facing error string surfaced via
705
+ * `JobUpdateCallbacks.onError` into a stable kind the UI can branch on.
706
+ *
707
+ * Match is case-insensitive against the message text. Returns
708
+ * `agent-unavailable` for any known billing/auth/invalid-key signal;
709
+ * `unknown` for everything else (timeouts, validation errors, transport).
710
+ */
711
+ declare function classifyJobError(message: string): JobErrorKind;
712
+
616
713
  declare class SolanaPaymentStrategy implements PaymentStrategy {
617
714
  readonly chain = "solana";
618
715
  calculateFee(amount: number, config: ProtocolConfigInput): number;
@@ -1092,10 +1189,17 @@ declare function makeCensor(): (value: unknown, path: string[]) => string;
1092
1189
 
1093
1190
  declare const RELAYS: string[];
1094
1191
  declare const KIND_APP_HANDLER = 31990;
1192
+ declare const KIND_LONG_FORM_ARTICLE = 30023;
1095
1193
  declare const KIND_JOB_REQUEST_BASE = 5000;
1096
1194
  declare const KIND_JOB_RESULT_BASE = 6000;
1097
1195
  declare const KIND_JOB_FEEDBACK = 7000;
1098
1196
  declare const DEFAULT_KIND_OFFSET = 100;
1197
+ /** Discovery tag attached to elisym agent policy events (kind 30023). */
1198
+ declare const POLICY_T_TAG = "elisym-policy";
1199
+ /** d-tag prefix for policy events: full d-tag = `<prefix><type>` (e.g. `elisym-policy-tos`). */
1200
+ declare const POLICY_D_TAG_PREFIX = "elisym-policy-";
1201
+ /** Validation regex for policy `type` slug. Lowercase ASCII + hyphen, 1-32 chars, no leading/trailing hyphen. */
1202
+ declare const POLICY_TYPE_REGEX: RegExp;
1099
1203
  /** Default job request kind (5000 + 100). */
1100
1204
  declare const KIND_JOB_REQUEST: number;
1101
1205
  /** Default job result kind (6000 + 100). */
@@ -1160,6 +1264,12 @@ declare const LIMITS: {
1160
1264
  readonly MAX_DESCRIPTION_LENGTH: 500;
1161
1265
  readonly MAX_AGENT_NAME_LENGTH: 64;
1162
1266
  readonly MAX_CAPABILITY_LENGTH: 64;
1267
+ readonly MAX_POLICY_CONTENT_LENGTH: 50000;
1268
+ readonly MAX_POLICIES_PER_AGENT: 12;
1269
+ readonly MAX_POLICY_TYPE_LENGTH: 32;
1270
+ readonly MAX_POLICY_TITLE_LENGTH: 120;
1271
+ readonly MAX_POLICY_SUMMARY_LENGTH: 280;
1272
+ readonly MAX_POLICY_VERSION_LENGTH: 32;
1163
1273
  };
1164
1274
 
1165
- export { type Agent, type AggregateNetworkStatsOptions, Asset, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, buildPaymentInstructions, calculateProtocolFee, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
1275
+ export { type Agent, type AgentPolicy, type AggregateNetworkStatsOptions, Asset, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobErrorKind, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, PoliciesService, type PolicyInput, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
package/dist/index.d.ts CHANGED
@@ -56,6 +56,37 @@ interface PaymentInfo {
56
56
  /** Display symbol (e.g. 'SOL', 'USDC'). */
57
57
  symbol?: string;
58
58
  }
59
+ /**
60
+ * Legal/operational policy published by an agent (NIP-23 long-form article,
61
+ * kind 30023). One event per `(pubkey, type)` slot; replaceable by `d`-tag.
62
+ *
63
+ * `type` is open vocabulary - common values: `tos`, `privacy`, `refund`,
64
+ * `aup`, `sla`, `dpa`, `jurisdiction`. Validation regex `POLICY_TYPE_REGEX`.
65
+ */
66
+ interface AgentPolicy {
67
+ type: string;
68
+ version: string;
69
+ title: string;
70
+ summary?: string;
71
+ /** Full markdown body. */
72
+ content: string;
73
+ /** NIP-19 `naddr` reference, e.g. for sharing or migration to dedicated kind. */
74
+ naddr: string;
75
+ /** Underlying NIP-23 d-tag (e.g. `elisym-policy-tos`). */
76
+ dTag: string;
77
+ /** Event `created_at` in unix seconds (NIP-23 spec: defaults to publication date). */
78
+ publishedAt: number;
79
+ eventId: string;
80
+ authorPubkey: string;
81
+ }
82
+ /** Input shape for `PoliciesService.publishPolicy`. */
83
+ interface PolicyInput {
84
+ type: string;
85
+ version: string;
86
+ title: string;
87
+ summary?: string;
88
+ content: string;
89
+ }
59
90
  /** Agent discovered from the network. */
60
91
  interface Agent {
61
92
  pubkey: string;
@@ -597,6 +628,33 @@ declare class PingService {
597
628
  sendPong(identity: ElisymIdentity, recipientPubkey: string, nonce: string): Promise<void>;
598
629
  }
599
630
 
631
+ declare class PoliciesService {
632
+ private pool;
633
+ constructor(pool: NostrPool);
634
+ /**
635
+ * Fetch all elisym policies published by `pubkey`. Verifies signatures,
636
+ * dedupes by d-tag (latest `created_at` wins), and returns sorted by `type`
637
+ * for deterministic UI rendering.
638
+ *
639
+ * Returns `[]` on empty result. Network errors propagate to the caller.
640
+ */
641
+ fetchPolicies(pubkey: string): Promise<AgentPolicy[]>;
642
+ /**
643
+ * Publish a policy as a NIP-23 long-form article (kind 30023). Replaces any
644
+ * existing policy of the same `type` for this pubkey via the addressable
645
+ * `(kind, pubkey, d-tag)` slot.
646
+ */
647
+ publishPolicy(identity: ElisymIdentity, input: PolicyInput): Promise<{
648
+ eventId: string;
649
+ naddr: string;
650
+ }>;
651
+ /**
652
+ * Tombstone a policy by publishing an empty replacement under the same
653
+ * `(kind, pubkey, d-tag)` slot. Readers skip events with empty content.
654
+ */
655
+ deletePolicy(identity: ElisymIdentity, type: string): Promise<string>;
656
+ }
657
+
600
658
  interface ElisymClientFullConfig extends ElisymClientConfig {
601
659
  payment?: PaymentStrategy;
602
660
  /** Custom upload URL for file uploads (defaults to nostr.build). */
@@ -608,11 +666,50 @@ declare class ElisymClient {
608
666
  readonly marketplace: MarketplaceService;
609
667
  readonly ping: PingService;
610
668
  readonly media: MediaService;
669
+ readonly policies: PoliciesService;
611
670
  readonly payment: PaymentStrategy;
612
671
  constructor(config?: ElisymClientFullConfig);
613
672
  close(): void;
614
673
  }
615
674
 
675
+ /**
676
+ * Customer-facing error feedback that arrives via `subscribeToJobUpdates`'s
677
+ * `onError` callback can come from many places:
678
+ *
679
+ * - The runtime's stable `Agent temporarily unavailable` string when the
680
+ * LLM health gate refuses a job (preflight) or an in-flight skill
681
+ * surfaced a billing/invalid signal.
682
+ * - The runtime's `Internal processing error` sanitization mask for any
683
+ * "<Provider> API error: ..." string that leaks out of an LLM call.
684
+ * - Raw script-skill failures the runtime forwards as-is when the
685
+ * message does not contain "API" - e.g. shell scripts that reach
686
+ * Anthropic's `count_tokens` endpoint and exit 1 with the body in
687
+ * stderr instead of using the canonical exit-42 contract.
688
+ * - Generic transport errors (timeouts, "Provider returned an error",
689
+ * rate-limit refusals, payment errors).
690
+ *
691
+ * Customers don't care which path produced the error - they care whether
692
+ * the agent is down (try later, payment recoverable) or something else
693
+ * went wrong (their input, their wallet, etc). This classifier collapses
694
+ * the first three categories into a single `agent-unavailable` kind so
695
+ * the UI can render one stable message regardless of how the underlying
696
+ * provider chose to surface the failure.
697
+ *
698
+ * Markers are kept as a permissive superset of every billing/auth phrase
699
+ * the CLI and skill scripts are known to emit. Adding a new marker is
700
+ * always safe; removing one risks classifying a real outage as `unknown`.
701
+ */
702
+ type JobErrorKind = 'agent-unavailable' | 'unknown';
703
+ /**
704
+ * Classify a customer-facing error string surfaced via
705
+ * `JobUpdateCallbacks.onError` into a stable kind the UI can branch on.
706
+ *
707
+ * Match is case-insensitive against the message text. Returns
708
+ * `agent-unavailable` for any known billing/auth/invalid-key signal;
709
+ * `unknown` for everything else (timeouts, validation errors, transport).
710
+ */
711
+ declare function classifyJobError(message: string): JobErrorKind;
712
+
616
713
  declare class SolanaPaymentStrategy implements PaymentStrategy {
617
714
  readonly chain = "solana";
618
715
  calculateFee(amount: number, config: ProtocolConfigInput): number;
@@ -1092,10 +1189,17 @@ declare function makeCensor(): (value: unknown, path: string[]) => string;
1092
1189
 
1093
1190
  declare const RELAYS: string[];
1094
1191
  declare const KIND_APP_HANDLER = 31990;
1192
+ declare const KIND_LONG_FORM_ARTICLE = 30023;
1095
1193
  declare const KIND_JOB_REQUEST_BASE = 5000;
1096
1194
  declare const KIND_JOB_RESULT_BASE = 6000;
1097
1195
  declare const KIND_JOB_FEEDBACK = 7000;
1098
1196
  declare const DEFAULT_KIND_OFFSET = 100;
1197
+ /** Discovery tag attached to elisym agent policy events (kind 30023). */
1198
+ declare const POLICY_T_TAG = "elisym-policy";
1199
+ /** d-tag prefix for policy events: full d-tag = `<prefix><type>` (e.g. `elisym-policy-tos`). */
1200
+ declare const POLICY_D_TAG_PREFIX = "elisym-policy-";
1201
+ /** Validation regex for policy `type` slug. Lowercase ASCII + hyphen, 1-32 chars, no leading/trailing hyphen. */
1202
+ declare const POLICY_TYPE_REGEX: RegExp;
1099
1203
  /** Default job request kind (5000 + 100). */
1100
1204
  declare const KIND_JOB_REQUEST: number;
1101
1205
  /** Default job result kind (6000 + 100). */
@@ -1160,6 +1264,12 @@ declare const LIMITS: {
1160
1264
  readonly MAX_DESCRIPTION_LENGTH: 500;
1161
1265
  readonly MAX_AGENT_NAME_LENGTH: 64;
1162
1266
  readonly MAX_CAPABILITY_LENGTH: 64;
1267
+ readonly MAX_POLICY_CONTENT_LENGTH: 50000;
1268
+ readonly MAX_POLICIES_PER_AGENT: 12;
1269
+ readonly MAX_POLICY_TYPE_LENGTH: 32;
1270
+ readonly MAX_POLICY_TITLE_LENGTH: 120;
1271
+ readonly MAX_POLICY_SUMMARY_LENGTH: 280;
1272
+ readonly MAX_POLICY_VERSION_LENGTH: 32;
1163
1273
  };
1164
1274
 
1165
- export { type Agent, type AggregateNetworkStatsOptions, Asset, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, buildPaymentInstructions, calculateProtocolFee, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
1275
+ export { type Agent, type AgentPolicy, type AggregateNetworkStatsOptions, Asset, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobErrorKind, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, PoliciesService, type PolicyInput, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
package/dist/index.js CHANGED
@@ -16,10 +16,14 @@ var RELAYS = [
16
16
  "wss://relay.snort.social"
17
17
  ];
18
18
  var KIND_APP_HANDLER = 31990;
19
+ var KIND_LONG_FORM_ARTICLE = 30023;
19
20
  var KIND_JOB_REQUEST_BASE = 5e3;
20
21
  var KIND_JOB_RESULT_BASE = 6e3;
21
22
  var KIND_JOB_FEEDBACK = 7e3;
22
23
  var DEFAULT_KIND_OFFSET = 100;
24
+ var POLICY_T_TAG = "elisym-policy";
25
+ var POLICY_D_TAG_PREFIX = "elisym-policy-";
26
+ var POLICY_TYPE_REGEX = /^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$/;
23
27
  var KIND_JOB_REQUEST = KIND_JOB_REQUEST_BASE + DEFAULT_KIND_OFFSET;
24
28
  var KIND_JOB_RESULT = KIND_JOB_RESULT_BASE + DEFAULT_KIND_OFFSET;
25
29
  function jobRequestKind(offset) {
@@ -72,7 +76,13 @@ var LIMITS = {
72
76
  MAX_CAPABILITIES: 20,
73
77
  MAX_DESCRIPTION_LENGTH: 500,
74
78
  MAX_AGENT_NAME_LENGTH: 64,
75
- MAX_CAPABILITY_LENGTH: 64
79
+ MAX_CAPABILITY_LENGTH: 64,
80
+ MAX_POLICY_CONTENT_LENGTH: 5e4,
81
+ MAX_POLICIES_PER_AGENT: 12,
82
+ MAX_POLICY_TYPE_LENGTH: 32,
83
+ MAX_POLICY_TITLE_LENGTH: 120,
84
+ MAX_POLICY_SUMMARY_LENGTH: 280,
85
+ MAX_POLICY_VERSION_LENGTH: 32
76
86
  };
77
87
  function getConfigDecoder() {
78
88
  return getStructDecoder([
@@ -2700,6 +2710,184 @@ var PingService = class _PingService {
2700
2710
  await this.pool.publishAll(pongEvent);
2701
2711
  }
2702
2712
  };
2713
+ function dTagFor(type) {
2714
+ return `${POLICY_D_TAG_PREFIX}${type}`;
2715
+ }
2716
+ function validatePolicyInput(input) {
2717
+ if (!POLICY_TYPE_REGEX.test(input.type)) {
2718
+ throw new Error(
2719
+ `Invalid policy type "${input.type}". Must be lowercase ASCII + hyphen, 1-${LIMITS.MAX_POLICY_TYPE_LENGTH} chars, no leading/trailing hyphen.`
2720
+ );
2721
+ }
2722
+ if (input.version.length === 0 || input.version.length > LIMITS.MAX_POLICY_VERSION_LENGTH) {
2723
+ throw new Error(
2724
+ `Policy version must be 1-${LIMITS.MAX_POLICY_VERSION_LENGTH} chars (got ${input.version.length}).`
2725
+ );
2726
+ }
2727
+ if (input.title.length === 0 || input.title.length > LIMITS.MAX_POLICY_TITLE_LENGTH) {
2728
+ throw new Error(
2729
+ `Policy title must be 1-${LIMITS.MAX_POLICY_TITLE_LENGTH} chars (got ${input.title.length}).`
2730
+ );
2731
+ }
2732
+ if (input.summary !== void 0 && input.summary.length > LIMITS.MAX_POLICY_SUMMARY_LENGTH) {
2733
+ throw new Error(
2734
+ `Policy summary too long: ${input.summary.length} chars (max ${LIMITS.MAX_POLICY_SUMMARY_LENGTH}).`
2735
+ );
2736
+ }
2737
+ if (input.content.length === 0) {
2738
+ throw new Error("Policy content cannot be empty.");
2739
+ }
2740
+ if (input.content.length > LIMITS.MAX_POLICY_CONTENT_LENGTH) {
2741
+ throw new Error(
2742
+ `Policy content too long: ${input.content.length} chars (max ${LIMITS.MAX_POLICY_CONTENT_LENGTH}).`
2743
+ );
2744
+ }
2745
+ }
2746
+ function parsePolicyEvent(event) {
2747
+ if (!verifyEvent(event)) {
2748
+ return null;
2749
+ }
2750
+ if (event.kind !== KIND_LONG_FORM_ARTICLE) {
2751
+ return null;
2752
+ }
2753
+ if (!event.content || event.content.length > LIMITS.MAX_POLICY_CONTENT_LENGTH) {
2754
+ return null;
2755
+ }
2756
+ const dTag = event.tags.find((tag) => tag[0] === "d")?.[1];
2757
+ if (!dTag || !dTag.startsWith(POLICY_D_TAG_PREFIX)) {
2758
+ return null;
2759
+ }
2760
+ const type = event.tags.find((tag) => tag[0] === "policy_type")?.[1];
2761
+ if (!type || !POLICY_TYPE_REGEX.test(type)) {
2762
+ return null;
2763
+ }
2764
+ const version = event.tags.find((tag) => tag[0] === "policy_version")?.[1];
2765
+ if (!version || version.length > LIMITS.MAX_POLICY_VERSION_LENGTH) {
2766
+ return null;
2767
+ }
2768
+ const title = event.tags.find((tag) => tag[0] === "title")?.[1];
2769
+ if (!title || title.length > LIMITS.MAX_POLICY_TITLE_LENGTH) {
2770
+ return null;
2771
+ }
2772
+ const summaryTag = event.tags.find((tag) => tag[0] === "summary")?.[1];
2773
+ const summary = summaryTag !== void 0 && summaryTag.length <= LIMITS.MAX_POLICY_SUMMARY_LENGTH ? summaryTag : void 0;
2774
+ const naddr = nip19.naddrEncode({
2775
+ kind: KIND_LONG_FORM_ARTICLE,
2776
+ pubkey: event.pubkey,
2777
+ identifier: dTag,
2778
+ relays: []
2779
+ });
2780
+ return {
2781
+ type,
2782
+ version,
2783
+ title,
2784
+ summary,
2785
+ content: event.content,
2786
+ naddr,
2787
+ dTag,
2788
+ publishedAt: event.created_at,
2789
+ eventId: event.id,
2790
+ authorPubkey: event.pubkey
2791
+ };
2792
+ }
2793
+ var PoliciesService = class {
2794
+ constructor(pool) {
2795
+ this.pool = pool;
2796
+ }
2797
+ /**
2798
+ * Fetch all elisym policies published by `pubkey`. Verifies signatures,
2799
+ * dedupes by d-tag (latest `created_at` wins), and returns sorted by `type`
2800
+ * for deterministic UI rendering.
2801
+ *
2802
+ * Returns `[]` on empty result. Network errors propagate to the caller.
2803
+ */
2804
+ async fetchPolicies(pubkey) {
2805
+ const filter = {
2806
+ kinds: [KIND_LONG_FORM_ARTICLE],
2807
+ authors: [pubkey],
2808
+ "#t": [POLICY_T_TAG]
2809
+ };
2810
+ const events = await this.pool.querySync(filter);
2811
+ const latestByDTag = /* @__PURE__ */ new Map();
2812
+ for (const event of events) {
2813
+ const dTag = event.tags.find((tag) => tag[0] === "d")?.[1] ?? "";
2814
+ const prev = latestByDTag.get(dTag);
2815
+ if (!prev || event.created_at > prev.created_at) {
2816
+ latestByDTag.set(dTag, event);
2817
+ }
2818
+ }
2819
+ const policies = [];
2820
+ for (const event of latestByDTag.values()) {
2821
+ const parsed = parsePolicyEvent(event);
2822
+ if (parsed) {
2823
+ policies.push(parsed);
2824
+ }
2825
+ }
2826
+ policies.sort((a, b) => a.type.localeCompare(b.type));
2827
+ return policies;
2828
+ }
2829
+ /**
2830
+ * Publish a policy as a NIP-23 long-form article (kind 30023). Replaces any
2831
+ * existing policy of the same `type` for this pubkey via the addressable
2832
+ * `(kind, pubkey, d-tag)` slot.
2833
+ */
2834
+ async publishPolicy(identity, input) {
2835
+ validatePolicyInput(input);
2836
+ const dTag = dTagFor(input.type);
2837
+ const tags = [
2838
+ ["d", dTag],
2839
+ ["t", POLICY_T_TAG],
2840
+ ["title", input.title],
2841
+ ["policy_type", input.type],
2842
+ ["policy_version", input.version]
2843
+ ];
2844
+ if (input.summary) {
2845
+ tags.push(["summary", input.summary]);
2846
+ }
2847
+ const event = finalizeEvent(
2848
+ {
2849
+ kind: KIND_LONG_FORM_ARTICLE,
2850
+ created_at: Math.floor(Date.now() / 1e3),
2851
+ tags,
2852
+ content: input.content
2853
+ },
2854
+ identity.secretKey
2855
+ );
2856
+ await this.pool.publishAll(event);
2857
+ const naddr = nip19.naddrEncode({
2858
+ kind: KIND_LONG_FORM_ARTICLE,
2859
+ pubkey: event.pubkey,
2860
+ identifier: dTag,
2861
+ relays: []
2862
+ });
2863
+ return { eventId: event.id, naddr };
2864
+ }
2865
+ /**
2866
+ * Tombstone a policy by publishing an empty replacement under the same
2867
+ * `(kind, pubkey, d-tag)` slot. Readers skip events with empty content.
2868
+ */
2869
+ async deletePolicy(identity, type) {
2870
+ if (!POLICY_TYPE_REGEX.test(type)) {
2871
+ throw new Error(`Invalid policy type "${type}".`);
2872
+ }
2873
+ const dTag = dTagFor(type);
2874
+ const event = finalizeEvent(
2875
+ {
2876
+ kind: KIND_LONG_FORM_ARTICLE,
2877
+ created_at: Math.floor(Date.now() / 1e3),
2878
+ tags: [
2879
+ ["d", dTag],
2880
+ ["t", POLICY_T_TAG],
2881
+ ["policy_type", type]
2882
+ ],
2883
+ content: ""
2884
+ },
2885
+ identity.secretKey
2886
+ );
2887
+ await this.pool.publishAll(event);
2888
+ return event.id;
2889
+ }
2890
+ };
2703
2891
 
2704
2892
  // src/primitives/bounded-set.ts
2705
2893
  var BoundedSet = class {
@@ -3008,6 +3196,7 @@ var ElisymClient = class {
3008
3196
  marketplace;
3009
3197
  ping;
3010
3198
  media;
3199
+ policies;
3011
3200
  payment;
3012
3201
  constructor(config = {}) {
3013
3202
  this.pool = new NostrPool(config.relays ?? RELAYS);
@@ -3015,12 +3204,39 @@ var ElisymClient = class {
3015
3204
  this.marketplace = new MarketplaceService(this.pool);
3016
3205
  this.ping = new PingService(this.pool);
3017
3206
  this.media = new MediaService(config.uploadUrl);
3207
+ this.policies = new PoliciesService(this.pool);
3018
3208
  this.payment = config.payment ?? new SolanaPaymentStrategy();
3019
3209
  }
3020
3210
  close() {
3021
3211
  this.pool.close();
3022
3212
  }
3023
3213
  };
3214
+
3215
+ // src/services/jobErrors.ts
3216
+ var AGENT_UNAVAILABLE_MARKERS = [
3217
+ "agent temporarily unavailable",
3218
+ "internal processing error",
3219
+ "invalid x-api-key",
3220
+ "invalid api key",
3221
+ "invalid_api_key",
3222
+ "x-api-key",
3223
+ "credit balance",
3224
+ "billing",
3225
+ "insufficient",
3226
+ "insufficient_quota",
3227
+ "authentication_error",
3228
+ "unauthorized",
3229
+ "unauthenticated"
3230
+ ];
3231
+ function classifyJobError(message) {
3232
+ const lower = message.toLowerCase();
3233
+ for (const marker of AGENT_UNAVAILABLE_MARKERS) {
3234
+ if (lower.includes(marker)) {
3235
+ return "agent-unavailable";
3236
+ }
3237
+ }
3238
+ return "unknown";
3239
+ }
3024
3240
  var DEFAULT_COMPUTE_UNIT_LIMIT2 = 2e5;
3025
3241
  var DEFAULT_PRIORITY_FEE_PERCENTILE2 = 75;
3026
3242
  var BASE_FEE_LAMPORTS_PER_SIGNATURE = 5000n;
@@ -3546,6 +3762,6 @@ function makeCensor() {
3546
3762
  };
3547
3763
  }
3548
3764
 
3549
- export { BoundedSet, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, ElisymIdentity, GlobalConfigSchema, INPUT_REDACT_PATHS, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_PING, KIND_PONG, KNOWN_ASSETS, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, NATIVE_SOL, NostrPool, PROTOCOL_PROGRAM_ID_DEVNET, PaymentRequestSchema, PingService, RELAYS, SECRET_REDACT_PATHS, SessionSpendLimitEntrySchema, SolanaPaymentStrategy, USDC_SOLANA_DEVNET, aggregateNetworkStats, assertExpiry, assertLamports, assetByKey, assetKey, buildPaymentInstructions, calculateProtocolFee, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, createSlidingWindowLimiter, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatAssetAmount, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parseAssetAmount, parsePaymentRequest, pickPercentileFee, resolveAssetFromPaymentRequest, resolveKnownAsset, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
3765
+ export { BoundedSet, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, ElisymIdentity, GlobalConfigSchema, INPUT_REDACT_PATHS, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, KNOWN_ASSETS, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, NATIVE_SOL, NostrPool, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, PaymentRequestSchema, PingService, PoliciesService, RELAYS, SECRET_REDACT_PATHS, SessionSpendLimitEntrySchema, SolanaPaymentStrategy, USDC_SOLANA_DEVNET, aggregateNetworkStats, assertExpiry, assertLamports, assetByKey, assetKey, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, createSlidingWindowLimiter, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatAssetAmount, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parseAssetAmount, parsePaymentRequest, pickPercentileFee, resolveAssetFromPaymentRequest, resolveKnownAsset, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
3550
3766
  //# sourceMappingURL=index.js.map
3551
3767
  //# sourceMappingURL=index.js.map