@agentfield/sdk 0.1.91 → 0.1.92-rc.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.
package/dist/index.d.ts CHANGED
@@ -45,6 +45,7 @@ declare class AIClient {
45
45
  getModel(options?: AIRequestOptions): _ai_sdk_provider.LanguageModelV3;
46
46
  private buildModel;
47
47
  private buildEmbeddingModel;
48
+ private openRouterHeaders;
48
49
  private getRateLimiter;
49
50
  private withRateLimitRetry;
50
51
  }
@@ -272,6 +273,14 @@ interface ExecutionStatusUpdate {
272
273
  progress?: number;
273
274
  statusReason?: string;
274
275
  }
276
+ interface RestartExecutionOptions {
277
+ scope?: 'workflow' | 'execution';
278
+ reuse?: 'succeeded-before' | 'all-succeeded' | 'none';
279
+ fork?: boolean;
280
+ reason?: string;
281
+ input?: Record<string, unknown>;
282
+ context?: Record<string, unknown>;
283
+ }
275
284
  declare class AgentFieldClient {
276
285
  private readonly http;
277
286
  private readonly config;
@@ -293,7 +302,11 @@ declare class AgentFieldClient {
293
302
  targetDid?: string;
294
303
  agentNodeDid?: string;
295
304
  agentNodeId?: string;
305
+ replaySourceRunId?: string;
306
+ replayBeforeExecutionId?: string;
307
+ replayMode?: string;
296
308
  }): Promise<T>;
309
+ restartExecution(executionId: string, options?: RestartExecutionOptions): Promise<any>;
297
310
  publishWorkflowEvent(event: {
298
311
  executionId: string;
299
312
  runId: string;
@@ -368,6 +381,9 @@ interface ExecutionMetadata {
368
381
  callerDid?: string;
369
382
  targetDid?: string;
370
383
  agentNodeDid?: string;
384
+ replaySourceRunId?: string;
385
+ replayBeforeExecutionId?: string;
386
+ replayMode?: string;
371
387
  }
372
388
  declare class ExecutionContext {
373
389
  readonly input: any;
@@ -869,6 +885,9 @@ interface AIConfig {
869
885
  embeddingModel?: string;
870
886
  apiKey?: string;
871
887
  baseUrl?: string;
888
+ openRouterSiteUrl?: string;
889
+ openRouterAppName?: string;
890
+ openRouterHeaders?: Record<string, string>;
872
891
  temperature?: number;
873
892
  maxTokens?: number;
874
893
  enableRateLimitRetry?: boolean;
@@ -1780,11 +1799,15 @@ declare class MediaRouter {
1780
1799
  interface OpenRouterMediaProviderOptions {
1781
1800
  apiKey?: string;
1782
1801
  baseUrl?: string;
1802
+ openRouterSiteUrl?: string;
1803
+ openRouterAppName?: string;
1804
+ openRouterHeaders?: Record<string, string>;
1783
1805
  }
1784
1806
  declare class OpenRouterMediaProvider implements MediaProvider {
1785
1807
  readonly name = "openrouter";
1786
1808
  readonly supportedModalities: string[];
1787
1809
  private readonly baseUrl;
1810
+ private readonly attributionHeaders;
1788
1811
  constructor(options?: OpenRouterMediaProviderOptions);
1789
1812
  /**
1790
1813
  * Seed the metadata cache for a model. Useful when running against test
package/dist/index.js CHANGED
@@ -34,6 +34,107 @@ var __export = (target, all) => {
34
34
  for (var name in all)
35
35
  __defProp(target, name, { get: all[name], enumerable: true });
36
36
  };
37
+
38
+ // src/ai/openrouterAttribution.ts
39
+ function isOpenRouterRequest(options) {
40
+ const provider = clean(options.provider)?.toLowerCase();
41
+ if (provider === "openrouter") {
42
+ return true;
43
+ }
44
+ const model = clean(options.model)?.toLowerCase();
45
+ if (model?.startsWith("openrouter/")) {
46
+ return true;
47
+ }
48
+ const baseUrl = clean(options.baseUrl)?.toLowerCase();
49
+ return Boolean(baseUrl?.includes("openrouter.ai"));
50
+ }
51
+ function openRouterAttributionEnabled(env = process.env) {
52
+ const raw = clean(env.AGENTFIELD_OPENROUTER_ATTRIBUTION);
53
+ if (!raw) {
54
+ return true;
55
+ }
56
+ return !["0", "false", "no", "off"].includes(raw.toLowerCase());
57
+ }
58
+ function resolveOpenRouterAttribution(options = {}) {
59
+ const env = options.env ?? process.env;
60
+ if (!openRouterAttributionEnabled(env)) {
61
+ return void 0;
62
+ }
63
+ const siteUrl = clean(options.siteUrl) ?? clean(env.AGENTFIELD_OPENROUTER_SITE_URL) ?? clean(env.OR_SITE_URL) ?? DEFAULT_OPENROUTER_SITE_URL;
64
+ const appName = clean(options.appName) ?? clean(env.AGENTFIELD_OPENROUTER_APP_NAME) ?? clean(env.OR_APP_NAME) ?? DEFAULT_OPENROUTER_APP_NAME;
65
+ return { siteUrl, appName };
66
+ }
67
+ function openRouterAttributionHeaders(options = {}) {
68
+ const resolved = resolveOpenRouterAttribution(options);
69
+ if (!resolved) {
70
+ return {};
71
+ }
72
+ return {
73
+ "HTTP-Referer": resolved.siteUrl,
74
+ "X-OpenRouter-Title": resolved.appName,
75
+ "X-Title": resolved.appName
76
+ };
77
+ }
78
+ function mergeOpenRouterAttributionHeaders(existing = {}, options = {}) {
79
+ const merged = {};
80
+ const lowerKeys = /* @__PURE__ */ new Set();
81
+ for (const [key, value] of Object.entries(existing)) {
82
+ const cleaned = clean(value);
83
+ if (!cleaned) {
84
+ continue;
85
+ }
86
+ merged[key] = cleaned;
87
+ lowerKeys.add(key.toLowerCase());
88
+ }
89
+ for (const [key, value] of Object.entries(openRouterAttributionHeaders(options))) {
90
+ if (!lowerKeys.has(key.toLowerCase())) {
91
+ merged[key] = value;
92
+ }
93
+ }
94
+ return merged;
95
+ }
96
+ function openRouterAttributionEnv(env = process.env) {
97
+ const resolved = resolveOpenRouterAttribution({ env });
98
+ if (!resolved) {
99
+ return {};
100
+ }
101
+ return {
102
+ AGENTFIELD_OPENROUTER_SITE_URL: resolved.siteUrl,
103
+ AGENTFIELD_OPENROUTER_APP_NAME: resolved.appName,
104
+ OR_SITE_URL: resolved.siteUrl,
105
+ OR_APP_NAME: resolved.appName
106
+ };
107
+ }
108
+ function applyOpenRouterAttributionEnv(env) {
109
+ if (!openRouterAttributionEnabled(env)) {
110
+ for (const key of [
111
+ "AGENTFIELD_OPENROUTER_SITE_URL",
112
+ "AGENTFIELD_OPENROUTER_APP_NAME",
113
+ "OR_SITE_URL",
114
+ "OR_APP_NAME"
115
+ ]) {
116
+ delete env[key];
117
+ }
118
+ return;
119
+ }
120
+ const attribution = openRouterAttributionEnv(env);
121
+ for (const [key, value] of Object.entries(attribution)) {
122
+ if (clean(env[key]) == null) {
123
+ env[key] = value;
124
+ }
125
+ }
126
+ }
127
+ function clean(value) {
128
+ const trimmed = value?.trim();
129
+ return trimmed ? trimmed : void 0;
130
+ }
131
+ var DEFAULT_OPENROUTER_SITE_URL, DEFAULT_OPENROUTER_APP_NAME;
132
+ var init_openrouterAttribution = __esm({
133
+ "src/ai/openrouterAttribution.ts"() {
134
+ DEFAULT_OPENROUTER_SITE_URL = "https://agentfield.ai";
135
+ DEFAULT_OPENROUTER_APP_NAME = "AgentField AI";
136
+ }
137
+ });
37
138
  function getZodConverter() {
38
139
  if (zodConverter !== void 0) {
39
140
  return zodConverter;
@@ -340,8 +441,10 @@ var init_claude = __esm({
340
441
  function runCli(cmd, options) {
341
442
  return new Promise((resolve2, reject) => {
342
443
  const [bin, ...args] = cmd;
444
+ const env = { ...process.env, ...options?.env };
445
+ applyOpenRouterAttributionEnv(env);
343
446
  const proc = spawn(bin, args, {
344
- env: { ...process.env, ...options?.env },
447
+ env,
345
448
  cwd: options?.cwd,
346
449
  stdio: ["pipe", "pipe", "pipe"]
347
450
  });
@@ -414,6 +517,7 @@ function extractFinalText(events) {
414
517
  }
415
518
  var init_cli = __esm({
416
519
  "src/harness/cli.ts"() {
520
+ init_openrouterAttribution();
417
521
  }
418
522
  });
419
523
 
@@ -566,6 +670,7 @@ var init_opencode = __esm({
566
670
  "src/harness/providers/opencode.ts"() {
567
671
  init_types();
568
672
  init_cli();
673
+ init_openrouterAttribution();
569
674
  OpenCodeProvider = class {
570
675
  bin;
571
676
  constructor(binPath = "opencode") {
@@ -593,6 +698,22 @@ USER REQUEST:
593
698
  ${prompt}`;
594
699
  }
595
700
  cmd.push(effectivePrompt);
701
+ const explicitModel = typeof options.model === "string" ? options.model : void 0;
702
+ if (explicitModel && isOpenRouterRequest({ model: explicitModel }) && !env.OPENCODE_CONFIG_CONTENT && !process.env.OPENCODE_CONFIG_CONTENT) {
703
+ const modelSlug = explicitModel.slice("openrouter/".length);
704
+ const headers = openRouterAttributionHeaders({ env: { ...process.env, ...env } });
705
+ if (modelSlug && Object.keys(headers).length > 0) {
706
+ env.OPENCODE_CONFIG_CONTENT = JSON.stringify({
707
+ provider: {
708
+ openrouter: {
709
+ models: {
710
+ [modelSlug]: { headers }
711
+ }
712
+ }
713
+ }
714
+ });
715
+ }
716
+ }
596
717
  const startApi = Date.now();
597
718
  try {
598
719
  const { stdout, stderr, exitCode } = await runCli(cmd, { env });
@@ -1671,6 +1792,7 @@ function toError(error) {
1671
1792
  }
1672
1793
 
1673
1794
  // src/ai/AIClient.ts
1795
+ init_openrouterAttribution();
1674
1796
  function repairJsonText(text2) {
1675
1797
  let cleaned = text2.trim();
1676
1798
  const codeBlockMatch = cleaned.match(/```(?:json)?\s*([\s\S]*?)```/);
@@ -1772,6 +1894,7 @@ var AIClient = class {
1772
1894
  buildModel(options) {
1773
1895
  const provider = options.provider ?? this.config.provider ?? "openai";
1774
1896
  const modelName = options.model ?? this.config.model ?? "gpt-4o";
1897
+ const openRouterHeaders = this.openRouterHeaders(provider, modelName);
1775
1898
  switch (provider) {
1776
1899
  case "anthropic": {
1777
1900
  const anthropic = createAnthropic({
@@ -1825,7 +1948,8 @@ var AIClient = class {
1825
1948
  case "openrouter": {
1826
1949
  const openrouter = createOpenAI({
1827
1950
  apiKey: this.config.apiKey,
1828
- baseURL: this.config.baseUrl ?? "https://openrouter.ai/api/v1"
1951
+ baseURL: this.config.baseUrl ?? "https://openrouter.ai/api/v1",
1952
+ headers: openRouterHeaders
1829
1953
  });
1830
1954
  return openrouter.chat(modelName);
1831
1955
  }
@@ -1841,7 +1965,8 @@ var AIClient = class {
1841
1965
  default: {
1842
1966
  const openai = createOpenAI({
1843
1967
  apiKey: this.config.apiKey,
1844
- baseURL: this.config.baseUrl
1968
+ baseURL: this.config.baseUrl,
1969
+ ...openRouterHeaders ? { headers: openRouterHeaders } : {}
1845
1970
  });
1846
1971
  return openai(modelName);
1847
1972
  }
@@ -1850,6 +1975,7 @@ var AIClient = class {
1850
1975
  buildEmbeddingModel(options) {
1851
1976
  const provider = options.provider ?? this.config.provider ?? "openai";
1852
1977
  const modelName = options.model ?? this.config.embeddingModel ?? "text-embedding-3-small";
1978
+ const openRouterHeaders = this.openRouterHeaders(provider, modelName);
1853
1979
  const noEmbeddingProviders = ["anthropic", "xai", "deepseek", "groq"];
1854
1980
  if (noEmbeddingProviders.includes(provider)) {
1855
1981
  throw new Error(`Embedding generation is not supported for ${provider} provider`);
@@ -1882,12 +2008,22 @@ var AIClient = class {
1882
2008
  default: {
1883
2009
  const openai = createOpenAI({
1884
2010
  apiKey: this.config.apiKey ?? (provider === "ollama" ? "ollama" : void 0),
1885
- baseURL: this.config.baseUrl ?? (provider === "openrouter" ? "https://openrouter.ai/api/v1" : provider === "ollama" ? "http://localhost:11434/v1" : void 0)
2011
+ baseURL: this.config.baseUrl ?? (provider === "openrouter" ? "https://openrouter.ai/api/v1" : provider === "ollama" ? "http://localhost:11434/v1" : void 0),
2012
+ ...openRouterHeaders ? { headers: openRouterHeaders } : {}
1886
2013
  });
1887
2014
  return openai.embedding(modelName);
1888
2015
  }
1889
2016
  }
1890
2017
  }
2018
+ openRouterHeaders(provider, model) {
2019
+ if (!isOpenRouterRequest({ provider, model, baseUrl: this.config.baseUrl })) {
2020
+ return void 0;
2021
+ }
2022
+ return mergeOpenRouterAttributionHeaders(this.config.openRouterHeaders, {
2023
+ siteUrl: this.config.openRouterSiteUrl,
2024
+ appName: this.config.openRouterAppName
2025
+ });
2026
+ }
1891
2027
  getRateLimiter() {
1892
2028
  if (!this.rateLimiter) {
1893
2029
  this.rateLimiter = new StatelessRateLimiter({
@@ -2187,6 +2323,9 @@ var AgentFieldClient = class {
2187
2323
  if (metadata?.targetDid) headers["X-Target-DID"] = metadata.targetDid;
2188
2324
  if (metadata?.agentNodeDid) headers["X-Agent-Node-DID"] = metadata.agentNodeDid;
2189
2325
  if (metadata?.agentNodeId) headers["X-Agent-Node-ID"] = metadata.agentNodeId;
2326
+ if (metadata?.replaySourceRunId) headers["X-AgentField-Replay-Source-Run-ID"] = metadata.replaySourceRunId;
2327
+ if (metadata?.replayBeforeExecutionId) headers["X-AgentField-Replay-Before-Execution-ID"] = metadata.replayBeforeExecutionId;
2328
+ if (metadata?.replayMode) headers["X-AgentField-Replay-Mode"] = metadata.replayMode;
2190
2329
  const bodyStr = JSON.stringify({ input });
2191
2330
  const authHeaders = this.didAuthenticator.signRequest(Buffer.from(bodyStr));
2192
2331
  try {
@@ -2213,6 +2352,44 @@ var AgentFieldClient = class {
2213
2352
  throw err;
2214
2353
  }
2215
2354
  }
2355
+ async restartExecution(executionId, options = {}) {
2356
+ if (!executionId) {
2357
+ throw new Error("executionId is required");
2358
+ }
2359
+ const body = {
2360
+ scope: options.scope ?? "workflow",
2361
+ reuse: options.reuse ?? "succeeded-before",
2362
+ fork: options.fork,
2363
+ reason: options.reason,
2364
+ input: options.input,
2365
+ context: options.context
2366
+ };
2367
+ const bodyStr = JSON.stringify(body);
2368
+ const authHeaders = this.didAuthenticator.signRequest(Buffer.from(bodyStr));
2369
+ try {
2370
+ const res = await this.http.post(
2371
+ `/api/v1/executions/${encodeURIComponent(executionId)}/restart`,
2372
+ bodyStr,
2373
+ { headers: this.mergeHeaders({ "Content-Type": "application/json", ...authHeaders }) }
2374
+ );
2375
+ return res.data;
2376
+ } catch (err) {
2377
+ const respData = err?.response?.data;
2378
+ if (respData) {
2379
+ const status = err.response.status;
2380
+ const msg = respData.message || respData.error || JSON.stringify(respData);
2381
+ const enriched = Object.assign(
2382
+ new Error(`restart execution ${executionId} failed (${status}): ${msg}`),
2383
+ {
2384
+ status,
2385
+ responseData: respData
2386
+ }
2387
+ );
2388
+ throw enriched;
2389
+ }
2390
+ throw err;
2391
+ }
2392
+ }
2216
2393
  async publishWorkflowEvent(event) {
2217
2394
  const payload = {
2218
2395
  execution_id: event.executionId,
@@ -2409,6 +2586,9 @@ var AgentFieldClient = class {
2409
2586
  if (metadata.targetDid) headers["x-target-did"] = metadata.targetDid;
2410
2587
  if (metadata.agentNodeDid) headers["x-agent-node-did"] = metadata.agentNodeDid;
2411
2588
  if (metadata.agentNodeId) headers["x-agent-node-id"] = metadata.agentNodeId;
2589
+ if (metadata.replaySourceRunId) headers["x-agentfield-replay-source-run-id"] = metadata.replaySourceRunId;
2590
+ if (metadata.replayBeforeExecutionId) headers["x-agentfield-replay-before-execution-id"] = metadata.replayBeforeExecutionId;
2591
+ if (metadata.replayMode) headers["x-agentfield-replay-mode"] = metadata.replayMode;
2412
2592
  return headers;
2413
2593
  }
2414
2594
  setDIDCredentials(did, privateKeyJwk) {
@@ -4116,7 +4296,10 @@ var Agent = class {
4116
4296
  callerDid: parentMetadata?.callerDid,
4117
4297
  targetDid: parentMetadata?.targetDid,
4118
4298
  agentNodeDid: parentMetadata?.agentNodeDid,
4119
- agentNodeId: this.config.nodeId
4299
+ agentNodeId: this.config.nodeId,
4300
+ replaySourceRunId: parentMetadata?.replaySourceRunId,
4301
+ replayBeforeExecutionId: parentMetadata?.replayBeforeExecutionId,
4302
+ replayMode: parentMetadata?.replayMode
4120
4303
  });
4121
4304
  this.executionLogger.system("agent.call.completed", "Remote agent call completed", {
4122
4305
  target,
@@ -4382,7 +4565,10 @@ var Agent = class {
4382
4565
  reasonerId: overrides?.reasonerId ?? normalized["x-reasoner-id"],
4383
4566
  callerDid: overrides?.callerDid ?? normalized["x-caller-did"],
4384
4567
  targetDid: overrides?.targetDid ?? normalized["x-target-did"],
4385
- agentNodeDid: overrides?.agentNodeDid ?? normalized["x-agent-node-did"] ?? normalized["x-agent-did"]
4568
+ agentNodeDid: overrides?.agentNodeDid ?? normalized["x-agent-node-did"] ?? normalized["x-agent-did"],
4569
+ replaySourceRunId: overrides?.replaySourceRunId ?? normalized["x-agentfield-replay-source-run-id"],
4570
+ replayBeforeExecutionId: overrides?.replayBeforeExecutionId ?? normalized["x-agentfield-replay-before-execution-id"],
4571
+ replayMode: overrides?.replayMode ?? normalized["x-agentfield-replay-mode"]
4386
4572
  };
4387
4573
  }
4388
4574
  handleHttpRequest(req, res) {
@@ -5644,6 +5830,7 @@ var MediaRouter = class {
5644
5830
  };
5645
5831
 
5646
5832
  // src/ai/OpenRouterMediaProvider.ts
5833
+ init_openrouterAttribution();
5647
5834
  var OPENROUTER_BASE = "https://openrouter.ai/api/v1";
5648
5835
  var DEFAULT_POLL_INTERVAL = 3e4;
5649
5836
  var DEFAULT_TIMEOUT = 6e5;
@@ -5735,9 +5922,14 @@ var OpenRouterMediaProvider = class {
5735
5922
  name = "openrouter";
5736
5923
  supportedModalities = ["image", "audio", "video"];
5737
5924
  baseUrl;
5925
+ attributionHeaders;
5738
5926
  constructor(options = {}) {
5739
5927
  const key = options.apiKey ?? process.env.OPENROUTER_API_KEY ?? "";
5740
5928
  this.baseUrl = options.baseUrl ?? OPENROUTER_BASE;
5929
+ this.attributionHeaders = mergeOpenRouterAttributionHeaders(options.openRouterHeaders, {
5930
+ siteUrl: options.openRouterSiteUrl,
5931
+ appName: options.openRouterAppName
5932
+ });
5741
5933
  if (!key) {
5742
5934
  throw new MediaProviderError("OpenRouter API key required: pass apiKey or set OPENROUTER_API_KEY", {
5743
5935
  provider: "openrouter"
@@ -5897,7 +6089,10 @@ var OpenRouterMediaProvider = class {
5897
6089
  } catch {
5898
6090
  }
5899
6091
  const dlRes = await fetch(videoUrl, {
5900
- headers: downloadHeaders,
6092
+ headers: mergeOpenRouterAttributionHeaders({
6093
+ ...this.attributionHeaders,
6094
+ ...downloadHeaders
6095
+ }),
5901
6096
  signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT),
5902
6097
  redirect: "error"
5903
6098
  });
@@ -6189,10 +6384,11 @@ var OpenRouterMediaProvider = class {
6189
6384
  const key = apiKeyStore.get(this);
6190
6385
  return fetch(url, {
6191
6386
  method: "POST",
6192
- headers: {
6387
+ headers: mergeOpenRouterAttributionHeaders({
6388
+ ...this.attributionHeaders,
6193
6389
  "Content-Type": "application/json",
6194
6390
  Authorization: `Bearer ${key}`
6195
- },
6391
+ }),
6196
6392
  body: JSON.stringify(body),
6197
6393
  signal: AbortSignal.timeout(API_TIMEOUT)
6198
6394
  });
@@ -6201,9 +6397,10 @@ var OpenRouterMediaProvider = class {
6201
6397
  const key = apiKeyStore.get(this);
6202
6398
  return fetch(url, {
6203
6399
  method: "GET",
6204
- headers: {
6400
+ headers: mergeOpenRouterAttributionHeaders({
6401
+ ...this.attributionHeaders,
6205
6402
  Authorization: `Bearer ${key}`
6206
- },
6403
+ }),
6207
6404
  signal: AbortSignal.timeout(API_TIMEOUT)
6208
6405
  });
6209
6406
  }