@schlenkr/ragents 0.1.18 → 0.1.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schlenkr/ragents",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "RAgents host: server, engine, plugins and tools without a source checkout",
5
5
  "keywords": [
6
6
  "agents",
@@ -71,14 +71,14 @@
71
71
  "yaml": "2.9.0"
72
72
  },
73
73
  "optionalDependencies": {
74
- "@schlenkr/ragents-tools-win32-x64": "0.1.18",
75
- "@schlenkr/ragents-tools-win32-arm64": "0.1.18",
76
- "@schlenkr/ragents-tools-darwin-x64": "0.1.18",
77
- "@schlenkr/ragents-tools-darwin-arm64": "0.1.18",
78
- "@schlenkr/ragents-tools-linux-x64": "0.1.18",
79
- "@schlenkr/ragents-tools-linux-arm64": "0.1.18"
74
+ "@schlenkr/ragents-tools-win32-x64": "0.1.19",
75
+ "@schlenkr/ragents-tools-win32-arm64": "0.1.19",
76
+ "@schlenkr/ragents-tools-darwin-x64": "0.1.19",
77
+ "@schlenkr/ragents-tools-darwin-arm64": "0.1.19",
78
+ "@schlenkr/ragents-tools-linux-x64": "0.1.19",
79
+ "@schlenkr/ragents-tools-linux-arm64": "0.1.19"
80
80
  },
81
81
  "ragents": {
82
- "hostVersion": "6f896323c8bdb2622d4dc9459a901949bf5fae33"
82
+ "hostVersion": "9fd1390d0bf180bd36be46f0409d318a223e6ef2"
83
83
  }
84
84
  }
@@ -2,7 +2,7 @@
2
2
  export interface AgentSettings {
3
3
  /** Retries after a retryable model error, with exponential backoff. */
4
4
  retry: { enabled: boolean; maxRetries: number; baseDelayMs: number };
5
- /** Timeout and retries of a single provider request; unset values leave the SDK defaults. */
5
+ /** Idle timeout (time without any received chunk) and retries of a single provider request; unset values leave the SDK defaults. */
6
6
  providerRequest: { timeoutMs: number; maxRetries?: number; maxRetryDelayMs: number };
7
7
  }
8
8
 
@@ -13,5 +13,5 @@ export interface AgentSettingsInput {
13
13
 
14
14
  export const agentSettings = (input: AgentSettingsInput = {}): AgentSettings => ({
15
15
  retry: { enabled: true, maxRetries: 3, baseDelayMs: 2000, ...input.retry },
16
- providerRequest: { timeoutMs: 300_000, maxRetryDelayMs: 60_000, ...input.providerRequest },
16
+ providerRequest: { timeoutMs: 600_000, maxRetryDelayMs: 60_000, ...input.providerRequest },
17
17
  });
@@ -33,6 +33,16 @@ async function runStream(model: Model<"openai-completions">, context: Context, o
33
33
  };
34
34
  const controller = new AbortController();
35
35
  const signal = options?.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
36
+ let idleTimer: ReturnType<typeof setTimeout> | undefined;
37
+ let idleExpired = false;
38
+ const restartIdleTimer = () => {
39
+ clearTimeout(idleTimer);
40
+ if (options?.timeoutMs === undefined) return;
41
+ idleTimer = setTimeout(() => {
42
+ idleExpired = true;
43
+ controller.abort();
44
+ }, options.timeoutMs);
45
+ };
36
46
  try {
37
47
  const retention = options?.cacheRetention ?? (getProviderEnvValue("AGENT_CACHE_RETENTION", options?.env) === "long" ? "long" : "short");
38
48
  const cacheControl = retention !== "none" && (model.compat?.cacheControlFormat === "anthropic" || model.id.startsWith("anthropic/"))
@@ -67,7 +77,6 @@ async function runStream(model: Model<"openai-completions">, context: Context, o
67
77
  maxRetries: options?.maxRetries ?? 0,
68
78
  streamRetries: 0,
69
79
  abortSignal: signal,
70
- timeout: options?.timeoutMs,
71
80
  stopWhen: stepCountIs(1),
72
81
  includeRawChunks: true,
73
82
  onError: () => {},
@@ -83,7 +92,9 @@ async function runStream(model: Model<"openai-completions">, context: Context, o
83
92
  let rawThinkingIndex: number | undefined;
84
93
  let hasFinishReason = false;
85
94
  let finished = false;
95
+ restartIdleTimer();
86
96
  for await (const part of result.fullStream) {
97
+ restartIdleTimer();
87
98
  switch (part.type) {
88
99
  case "raw": {
89
100
  const chunk = part.rawValue as { id?: string; model?: string; choices?: Array<{ finish_reason?: string | null; delta?: {
@@ -216,9 +227,11 @@ async function runStream(model: Model<"openai-completions">, context: Context, o
216
227
  } catch (error) {
217
228
  controller.abort();
218
229
  output.stopReason = options?.signal?.aborted ? "aborted" : "error";
219
- output.errorMessage = formatProviderError(normalizeProviderError(error), model.provider === "relay" ? `Relay ${model.baseUrl}` : undefined);
230
+ const failure = idleExpired ? new Error(`Timeout: no data from the provider for ${options?.timeoutMs} ms`) : error;
231
+ output.errorMessage = formatProviderError(normalizeProviderError(failure), model.provider === "relay" ? `Relay ${model.baseUrl}` : undefined);
220
232
  events.push({ type: "error", reason: output.stopReason, error: output });
221
233
  } finally {
234
+ clearTimeout(idleTimer);
222
235
  events.end();
223
236
  }
224
237
  }
@@ -89,7 +89,8 @@ export interface StreamOptions {
89
89
  */
90
90
  headers?: ProviderHeaders;
91
91
  /**
92
- * HTTP request timeout in milliseconds for providers/SDKs that support it.
92
+ * Timeout in milliseconds for providers/SDKs that support it. The openai-completions
93
+ * stream counts it as idle time: any received chunk restarts it, so an active stream never expires.
93
94
  * For example, OpenAI and Anthropic SDK clients default to 10 minutes.
94
95
  */
95
96
  timeoutMs?: number;