@stigg/agent-sdk-js 0.0.0-stage → 1.0.1

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.
Files changed (82) hide show
  1. package/README.md +1147 -2
  2. package/dist/bindings/client/core/registry.d.ts +12 -0
  3. package/dist/bindings/client/core/registry.js +22 -0
  4. package/dist/bindings/client/core/types.d.ts +117 -0
  5. package/dist/bindings/client/core/types.js +13 -0
  6. package/dist/bindings/client/core/wrap-client.d.ts +6 -0
  7. package/dist/bindings/client/core/wrap-client.js +258 -0
  8. package/dist/bindings/client/gateways/litellm/litellm-recipe.d.ts +17 -0
  9. package/dist/bindings/client/gateways/litellm/litellm-recipe.js +171 -0
  10. package/dist/bindings/client/gateways/litellm/types.d.ts +30 -0
  11. package/dist/bindings/client/gateways/litellm/types.js +2 -0
  12. package/dist/bindings/client/gateways/openrouter/openrouter-recipe.d.ts +15 -0
  13. package/dist/bindings/client/gateways/openrouter/openrouter-recipe.js +141 -0
  14. package/dist/bindings/client/gateways/openrouter/types.d.ts +29 -0
  15. package/dist/bindings/client/gateways/openrouter/types.js +2 -0
  16. package/dist/bindings/client/providers/anthropic/anthropic-recipe.d.ts +30 -0
  17. package/dist/bindings/client/providers/anthropic/anthropic-recipe.js +79 -0
  18. package/dist/bindings/client/providers/gemini/gemini-recipe.d.ts +54 -0
  19. package/dist/bindings/client/providers/gemini/gemini-recipe.js +243 -0
  20. package/dist/bindings/client/providers/openai/openai-recipe.d.ts +43 -0
  21. package/dist/bindings/client/providers/openai/openai-recipe.js +80 -0
  22. package/dist/bindings/client/providers/typesafe/typesafe-recipe.d.ts +33 -0
  23. package/dist/bindings/client/providers/typesafe/typesafe-recipe.js +73 -0
  24. package/dist/bindings/proxy/headers.d.ts +6 -0
  25. package/dist/bindings/proxy/headers.js +12 -0
  26. package/dist/bindings/proxy/index.d.ts +21 -0
  27. package/dist/bindings/proxy/index.js +18 -0
  28. package/dist/bindings/proxy/types.d.ts +8 -0
  29. package/dist/bindings/proxy/types.js +2 -0
  30. package/dist/bindings/shared/estimate.d.ts +27 -0
  31. package/dist/bindings/shared/estimate.js +38 -0
  32. package/dist/bindings/shared/meter-stream.d.ts +18 -0
  33. package/dist/bindings/shared/meter-stream.js +151 -0
  34. package/dist/bindings/shared/token-usage.d.ts +148 -0
  35. package/dist/bindings/shared/token-usage.js +414 -0
  36. package/dist/bindings/shared/types.d.ts +79 -0
  37. package/dist/bindings/shared/types.js +2 -0
  38. package/dist/bindings/shared/weighted-metrics.d.ts +37 -0
  39. package/dist/bindings/shared/weighted-metrics.js +44 -0
  40. package/dist/config.d.ts +136 -0
  41. package/dist/config.js +97 -0
  42. package/dist/core/context.d.ts +151 -0
  43. package/dist/core/context.js +154 -0
  44. package/dist/core/dimensions.d.ts +22 -0
  45. package/dist/core/dimensions.js +47 -0
  46. package/dist/core/hooks.d.ts +21 -0
  47. package/dist/core/hooks.js +47 -0
  48. package/dist/core/session.d.ts +161 -0
  49. package/dist/core/session.js +403 -0
  50. package/dist/decision-text.d.ts +15 -0
  51. package/dist/decision-text.js +54 -0
  52. package/dist/engine/composite-engine.d.ts +72 -0
  53. package/dist/engine/composite-engine.js +135 -0
  54. package/dist/engine/create-engine.d.ts +16 -0
  55. package/dist/engine/create-engine.js +93 -0
  56. package/dist/engine/decision.d.ts +37 -0
  57. package/dist/engine/decision.js +128 -0
  58. package/dist/engine/engine.d.ts +166 -0
  59. package/dist/engine/engine.js +11 -0
  60. package/dist/engine/node-sdk-engine.d.ts +125 -0
  61. package/dist/engine/node-sdk-engine.js +262 -0
  62. package/dist/engine/report.d.ts +106 -0
  63. package/dist/engine/report.js +185 -0
  64. package/dist/engine/rest-governance-engine.d.ts +47 -0
  65. package/dist/engine/rest-governance-engine.js +220 -0
  66. package/dist/errors.d.ts +78 -0
  67. package/dist/errors.js +151 -0
  68. package/dist/headers.d.ts +27 -0
  69. package/dist/headers.js +63 -0
  70. package/dist/index.d.ts +48 -0
  71. package/dist/index.js +85 -0
  72. package/dist/internal.d.ts +33 -0
  73. package/dist/internal.js +81 -0
  74. package/dist/logger.d.ts +15 -0
  75. package/dist/logger.js +20 -0
  76. package/dist/sdk-identity.d.ts +36 -0
  77. package/dist/sdk-identity.js +43 -0
  78. package/dist/stigg-agent-sdk.d.ts +242 -0
  79. package/dist/stigg-agent-sdk.js +594 -0
  80. package/dist/types.d.ts +531 -0
  81. package/dist/types.js +97 -0
  82. package/package.json +80 -3
@@ -0,0 +1,242 @@
1
+ import { type ResolvedConfig, type StiggAgentSDKOptions, type StiggTarget } from './config';
2
+ import { type EngineResolution, type GovernanceEngine } from './engine/engine';
3
+ import type { StiggContext } from './core/context';
4
+ import type { GovernanceSummary } from './core/session';
5
+ import type { Metrics, ClientOptions, DeregisterInput, GovernanceDecision, GovernedClient, PathsOf, IngestContext, IngestResult, RegisterInput } from './types';
6
+ import type { GovernanceHeaders } from './headers';
7
+ /**
8
+ * Recipes are data - method paths and usage extractors - so wiring them here costs nothing at
9
+ * runtime and pulls in no vendor package. An orchestration adapter is different: it needs its
10
+ * framework loaded, so it stays an explicit subpath import.
11
+ */
12
+ /**
13
+ * Order matters: the gateways are matched before the plain OpenAI adapter, because every one of
14
+ * them *is* an OpenAI client by shape and only the base URL says which. The bare adapter would
15
+ * otherwise claim them and lose what only a gateway knows - the model that actually served after
16
+ * routing, and the gateway's own request id.
17
+ *
18
+ * Matching them costs nothing in units: they report what the gateway stated and leave what it is
19
+ * worth to the run's mapper, like every other vendor. Billing the `cost` they add rather than the
20
+ * tokens is that mapper's business, and stays the caller's to decide.
21
+ */
22
+ export declare const DEFAULT_RECIPES: ({
23
+ vendor: string;
24
+ metrics: readonly ["input_tokens", "output_tokens", "cache_read_input_tokens", "cache_creation_input_tokens", "total_tokens"];
25
+ totalTokensMetric: "total_tokens";
26
+ matches: (client: unknown) => boolean;
27
+ methods: {
28
+ path: string[];
29
+ extractUsage: (result: any) => {
30
+ metrics: Metrics;
31
+ usage: import("./types").TokenUsage;
32
+ raw: any;
33
+ } | undefined;
34
+ attachStream: (stream: any, ingest: (measurement: import("./types").Measurement) => void) => void;
35
+ }[];
36
+ } | {
37
+ vendor: string;
38
+ metrics: readonly ["promptTokenCount", "candidatesTokenCount", "cachedContentTokenCount", "thoughtsTokenCount", "toolUsePromptTokenCount", "totalTokenCount"];
39
+ totalTokensMetric: "totalTokenCount";
40
+ matches: (client: unknown) => boolean;
41
+ methods: ({
42
+ path: readonly ["models", "generateContent"];
43
+ extractUsage: (result: any) => import("./types").Measurement | undefined;
44
+ attachStream: (stream: any, ingest: (measurement: import("./types").Measurement) => void) => void;
45
+ } | {
46
+ path: readonly ["models", "generateContentStream"];
47
+ extractUsage: (result: any) => import("./types").Measurement | undefined;
48
+ attachStream: (stream: any, ingest: (measurement: import("./types").Measurement) => void) => void;
49
+ })[];
50
+ } | {
51
+ vendor: string;
52
+ metrics: readonly ["promptTokenCount", "candidatesTokenCount", "cachedContentTokenCount", "thoughtsTokenCount", "toolUsePromptTokenCount", "totalTokenCount"];
53
+ totalTokensMetric: "totalTokenCount";
54
+ matches: (client: unknown) => boolean;
55
+ methods: ({
56
+ path: readonly ["sendMessage"];
57
+ event: string;
58
+ extractUsage: (result: any) => import("./types").Measurement | undefined;
59
+ attachStream: (stream: any, ingest: (measurement: import("./types").Measurement) => void) => void;
60
+ } | {
61
+ path: readonly ["sendMessageStream"];
62
+ event: string;
63
+ extractUsage: (result: any) => import("./types").Measurement | undefined;
64
+ attachStream: (stream: any, ingest: (measurement: import("./types").Measurement) => void) => void;
65
+ })[];
66
+ } | {
67
+ vendor: string;
68
+ metrics: readonly ["prompt_tokens", "completion_tokens", "input_tokens", "output_tokens", "cached_tokens", "total_tokens"];
69
+ totalTokensMetric: "total_tokens";
70
+ matches: (client: unknown) => boolean;
71
+ methods: {
72
+ path: ("create" | "chat" | "completions" | "responses")[];
73
+ extractUsage: (result: any) => {
74
+ metrics: Metrics;
75
+ usage: import("./types").TokenUsage;
76
+ raw: any;
77
+ } | undefined;
78
+ attachStream: (stream: any, ingest: (measurement: import("./types").Measurement) => void) => void;
79
+ }[];
80
+ } | import("./bindings/client/core/types").ClientRecipe<"cached_tokens" | "prompt_tokens" | "completion_tokens" | "input_tokens" | "output_tokens" | "total_tokens" | "cost"> | {
81
+ vendor: string;
82
+ metrics: readonly ["input_tokens", "output_tokens", "total_tokens"];
83
+ totalTokensMetric: "total_tokens";
84
+ matches: (client: unknown) => boolean;
85
+ methods: {
86
+ path: string[];
87
+ extractUsage: (result: any) => {
88
+ metrics: Metrics;
89
+ usage: import("./types").TokenUsage;
90
+ raw: any;
91
+ } | undefined;
92
+ }[];
93
+ })[];
94
+ export declare class StiggAgentSDK {
95
+ readonly config: ResolvedConfig;
96
+ private readonly clients;
97
+ /** Every session this SDK handed out, so `flush()` can drain all of them at once. */
98
+ private readonly sessions;
99
+ /** The session the no-client paths share. Built on first use. */
100
+ private loose?;
101
+ /**
102
+ * `customer:agent` -> what was last said about that agent, so a repeat of the same description
103
+ * is not written again per run. The value is a fingerprint of the describable attributes, not
104
+ * an id: the id is in the key.
105
+ */
106
+ private readonly registered;
107
+ /**
108
+ * Bare registrations still on the wire, so the burst of runs that opens a process writes once
109
+ * rather than once each. Only the memoized path is shared - see `register`.
110
+ */
111
+ private readonly registering;
112
+ private started?;
113
+ private engineState?;
114
+ /**
115
+ * Synchronous - nothing here touches the network. The engine is built on the first call that
116
+ * needs it, so there is no awaited setup step to forget; `await init()` forces it early.
117
+ *
118
+ * Where this SDK sends its traffic comes first, because it is the only thing that cannot be
119
+ * inferred: a server key, a `{ baseUrl }` target that needs none, or nothing at all to read
120
+ * `STIGG_SERVER_API_KEY`. See {@link StiggTarget}. A key that belongs to somewhere other than
121
+ * the hosted API names that URL second - the two together are one idea, so neither is buried
122
+ * among the tuning knobs that follow.
123
+ *
124
+ * Construct one per environment and share it - the engine's cache and its connection pool are
125
+ * per instance, so a second one for the same environment is wasted rather than wrong.
126
+ */
127
+ constructor(target?: StiggTarget, baseUrl?: string, options?: StiggAgentSDKOptions);
128
+ /** The same, for a target that already carries its URL - or one on the hosted API. */
129
+ constructor(target?: StiggTarget, options?: StiggAgentSDKOptions);
130
+ /** Releases what this SDK's engine holds open. */
131
+ close(): Promise<void>;
132
+ /**
133
+ * Forces the engine to resolve now and reports which client serves what. Optional - every
134
+ * async call below does it anyway - but useful when you want the answer before the first run.
135
+ */
136
+ init(): Promise<EngineResolution>;
137
+ /** Undefined until the engine has resolved. `init()` returns it directly. */
138
+ get resolution(): EngineResolution | undefined;
139
+ /** Available after the engine has resolved; the bindings that need it only run after that. */
140
+ get engine(): GovernanceEngine;
141
+ /**
142
+ * Gives the agent an identity, a budget, and a place in the tree, and returns the agent id to
143
+ * open a run against.
144
+ *
145
+ * The id is the one you passed: nothing about the run depends on this call having happened, so
146
+ * returning it is a convenience rather than a handle. Skip `register` entirely and the agent
147
+ * has no entity - the run still works, and checks and usage apply to the customer instead.
148
+ *
149
+ * Idempotent, and remembered per process: an upsert is cheap, but it is still a write, so
150
+ * calling this on a hot path does not repeat it. A call carrying a budget or a parent always
151
+ * writes, because that is a deliberate change rather than a formality.
152
+ *
153
+ * `run.start(runOptions, agentOptions)` calls this for you with the run's own scope, which is
154
+ * the usual way in; reach for it directly to provision an agent no run is about to use.
155
+ */
156
+ register(input: RegisterInput): Promise<string>;
157
+ /**
158
+ * Removes the agent's entity. Optional, mirrors `register`, and never relied on: it may never
159
+ * fire - a crash, an abandoned stream, an interrupt that is never resumed - which is why warm
160
+ * state has a TTL rather than waiting to be released.
161
+ */
162
+ deregister(input: DeregisterInput): Promise<void>;
163
+ /**
164
+ * Governs a vendor client and hands back a copy whose calls are checked and metered.
165
+ *
166
+ * The whole lifecycle, in one step. `stiggContext` here is the default for every call through
167
+ * this client; any single call overrides it by putting its own `stiggContext` in the vendor's
168
+ * parameters. The client you passed is never mutated, so it keeps working ungoverned.
169
+ *
170
+ * The vendor is recognised from the client's own shape and base URL rather than named; pass
171
+ * `recipe` only for a vendor the built-ins cannot identify.
172
+ *
173
+ * Warms the entitlement cache before returning when the context names both a customer and an
174
+ * entitlement, so the calls that follow read local state. Nothing is cached in this package -
175
+ * see {@link GovernanceSession.warmUp} for which cache that is and when there is one at all.
176
+ */
177
+ wrap<T extends object, O extends ClientOptions>(client: T, options?: O): GovernedClient<T, O['stiggContext'], PathsOf<O['recipe'], T>>;
178
+ /**
179
+ * Hangs the governance handle off the wrapped client. Refuses to overwrite a `stigg` the vendor
180
+ * already has: silently replacing one of its own properties would be a worse surprise.
181
+ */
182
+ private attachGovernance;
183
+ /**
184
+ * The gate, with no client to wrap - what a framework binding reaches for, and what the gateway
185
+ * example checks with before it proxies.
186
+ */
187
+ check(context: StiggContext, requestedUsage?: number): Promise<GovernanceDecision>;
188
+ /** The meter, with no client to wrap. Metrics already in Stigg's own vocabulary. */
189
+ report(context: StiggContext, metrics: Metrics): Promise<IngestResult>;
190
+ /** The `x-stigg-*` attribution for work continuing in another process, with no client involved. */
191
+ governanceHeaders(context: StiggContext): GovernanceHeaders;
192
+ /**
193
+ * The policy a context falls back to when neither the call nor `wrap` named one.
194
+ *
195
+ * Both fields are always set - the config schema defaults them - so this is the one place a
196
+ * constructor option becomes the behaviour of a call. Before it existed the options were parsed,
197
+ * stored, and never read: every context fell through to the context module's own defaults, and a
198
+ * client constructed with `checkErrorAction: 'deny'` failed open on every call it gated.
199
+ */
200
+ private get contextDefaults();
201
+ private newSession;
202
+ /** The session the no-client paths share, built on first use so an unused SDK builds none. */
203
+ private standalone;
204
+ /**
205
+ * Returns the decision when `err` is a governance refusal, so a catch block is one line and the
206
+ * caller needs no import to tell a denial from a real failure.
207
+ */
208
+ denial(err: unknown): GovernanceDecision | undefined;
209
+ /**
210
+ * The gateway side of the split lifecycle: ingest usage a proxy observed, attributed from the
211
+ * headers the application sent with the request. Ingest only - a gateway sees requests, not
212
+ * runs, so there is nothing here to check against.
213
+ */
214
+ ingestFromHeaders(headers: Record<string, string | string[] | undefined>, input: IngestContext & {
215
+ usage: unknown;
216
+ idempotencyKey: string;
217
+ /** This report's outcome, including a failed one. The gateway's stand-in for a run hook. */
218
+ onIngest?: (result: IngestResult) => void;
219
+ }): Promise<IngestResult>;
220
+ /**
221
+ * A probe that failed with nobody waiting on it.
222
+ *
223
+ * `wrap()` returns before the engine resolves, so this is the one path where a startup failure
224
+ * has no caller to reject towards. Swallowing it silently would leave a client that looks
225
+ * governed and cannot check; letting it reject unobserved ends the process.
226
+ */
227
+ private reportStartupFailure;
228
+ /** `onError` is the application's too, and there is nowhere left to report its failure to. */
229
+ private reportIngestFailure;
230
+ /**
231
+ * Drains every wrapped client's in-flight ingests. Explicit because an exit hook does not fire
232
+ * in a request-scoped or serverless runtime.
233
+ *
234
+ * A single client drains on its own with `client.stigg.flush()`; this is the process-wide one,
235
+ * for a shutdown that does not know which clients exist.
236
+ */
237
+ flush(options?: {
238
+ close?: boolean;
239
+ }): Promise<GovernanceSummary[]>;
240
+ /** Builds the engine once, on first need. Concurrent callers share the same attempt. */
241
+ private ensureStarted;
242
+ }