@tangle-network/agent-runtime 0.11.1 → 0.12.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/agent.d.ts +164 -2
- package/dist/agent.js +108 -0
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +26 -0
- package/dist/index.js +63 -18
- package/dist/index.js.map +1 -1
- package/package.json +11 -22
package/dist/index.d.ts
CHANGED
|
@@ -35,12 +35,38 @@ declare function createSandboxPromptBackend<TBox, TInput extends AgentBackendInp
|
|
|
35
35
|
getSessionId?: (box: TBox, input: TInput) => string | undefined;
|
|
36
36
|
}): AgentExecutionBackend<TInput>;
|
|
37
37
|
/** @stable */
|
|
38
|
+
/**
|
|
39
|
+
* Retry policy for transient transport errors (rate limits, upstream
|
|
40
|
+
* timeouts). Defaults to 5 attempts with exponential backoff starting at
|
|
41
|
+
* 1s, ±25% jitter, capped at 30s. Set `maxAttempts: 1` to disable retries.
|
|
42
|
+
*
|
|
43
|
+
* Retried status codes:
|
|
44
|
+
* - 408 Request Timeout
|
|
45
|
+
* - 425 Too Early
|
|
46
|
+
* - 429 Too Many Requests
|
|
47
|
+
* - 500 / 502 / 503 / 504 — upstream transient failures
|
|
48
|
+
*
|
|
49
|
+
* Hard failures (401, 403, 4xx other than the above) propagate immediately.
|
|
50
|
+
*/
|
|
51
|
+
interface BackendRetryPolicy {
|
|
52
|
+
/** Total attempts including the first try. Default 5. */
|
|
53
|
+
maxAttempts?: number;
|
|
54
|
+
/** Initial backoff in ms before the second attempt. Default 1000. */
|
|
55
|
+
initialBackoffMs?: number;
|
|
56
|
+
/** Hard ceiling on backoff in ms. Default 30000. */
|
|
57
|
+
maxBackoffMs?: number;
|
|
58
|
+
/** Jitter fraction in [0, 1]. Default 0.25 (±25%). */
|
|
59
|
+
jitter?: number;
|
|
60
|
+
/** Status codes that trigger a retry. Default: 408, 425, 429, 500, 502, 503, 504. */
|
|
61
|
+
retryStatuses?: ReadonlyArray<number>;
|
|
62
|
+
}
|
|
38
63
|
declare function createOpenAICompatibleBackend<TInput extends AgentBackendInput = AgentBackendInput>(options: {
|
|
39
64
|
apiKey: string;
|
|
40
65
|
baseUrl: string;
|
|
41
66
|
model: string;
|
|
42
67
|
kind?: string;
|
|
43
68
|
fetchImpl?: typeof fetch;
|
|
69
|
+
retry?: BackendRetryPolicy;
|
|
44
70
|
}): AgentExecutionBackend<TInput>;
|
|
45
71
|
|
|
46
72
|
/**
|
package/dist/index.js
CHANGED
|
@@ -106,33 +106,78 @@ function createSandboxPromptBackend(options) {
|
|
|
106
106
|
}
|
|
107
107
|
};
|
|
108
108
|
}
|
|
109
|
+
var DEFAULT_RETRY_STATUSES = [408, 425, 429, 500, 502, 503, 504];
|
|
110
|
+
function pickRetryDelayMs(attempt, policy) {
|
|
111
|
+
const exp = policy.initialBackoffMs * 2 ** (attempt - 1);
|
|
112
|
+
const capped = Math.min(exp, policy.maxBackoffMs);
|
|
113
|
+
const jitter = capped * policy.jitter * (Math.random() * 2 - 1);
|
|
114
|
+
return Math.max(0, Math.round(capped + jitter));
|
|
115
|
+
}
|
|
116
|
+
function sleep(ms, signal) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
if (signal?.aborted) {
|
|
119
|
+
reject(signal.reason ?? new Error("aborted"));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const t = setTimeout(() => {
|
|
123
|
+
signal?.removeEventListener("abort", onAbort);
|
|
124
|
+
resolve();
|
|
125
|
+
}, ms);
|
|
126
|
+
const onAbort = () => {
|
|
127
|
+
clearTimeout(t);
|
|
128
|
+
reject(signal?.reason ?? new Error("aborted"));
|
|
129
|
+
};
|
|
130
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
131
|
+
});
|
|
132
|
+
}
|
|
109
133
|
function createOpenAICompatibleBackend(options) {
|
|
110
134
|
const fetcher = options.fetchImpl ?? fetch;
|
|
111
135
|
const kind = options.kind ?? "tcloud";
|
|
136
|
+
const retryPolicy = {
|
|
137
|
+
maxAttempts: options.retry?.maxAttempts ?? 5,
|
|
138
|
+
initialBackoffMs: options.retry?.initialBackoffMs ?? 1e3,
|
|
139
|
+
maxBackoffMs: options.retry?.maxBackoffMs ?? 3e4,
|
|
140
|
+
jitter: options.retry?.jitter ?? 0.25,
|
|
141
|
+
retryStatuses: options.retry?.retryStatuses ?? DEFAULT_RETRY_STATUSES
|
|
142
|
+
};
|
|
112
143
|
return {
|
|
113
144
|
kind,
|
|
114
145
|
start(_input, context) {
|
|
115
146
|
return newRuntimeSession(kind, context.requestedSessionId);
|
|
116
147
|
},
|
|
117
148
|
async *stream(input, context) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
149
|
+
let response;
|
|
150
|
+
let lastStatus = 0;
|
|
151
|
+
for (let attempt = 1; attempt <= retryPolicy.maxAttempts; attempt++) {
|
|
152
|
+
response = await fetcher(`${options.baseUrl.replace(/\/$/, "")}/chat/completions`, {
|
|
153
|
+
method: "POST",
|
|
154
|
+
headers: {
|
|
155
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
156
|
+
"Content-Type": "application/json"
|
|
157
|
+
},
|
|
158
|
+
body: JSON.stringify({
|
|
159
|
+
model: options.model,
|
|
160
|
+
stream: true,
|
|
161
|
+
messages: input.messages ?? [
|
|
162
|
+
{ role: "user", content: input.message ?? context.task.intent }
|
|
163
|
+
]
|
|
164
|
+
}),
|
|
165
|
+
signal: context.signal
|
|
166
|
+
});
|
|
167
|
+
if (response.ok) break;
|
|
168
|
+
lastStatus = response.status;
|
|
169
|
+
if (!retryPolicy.retryStatuses.includes(response.status)) break;
|
|
170
|
+
if (attempt === retryPolicy.maxAttempts) break;
|
|
171
|
+
try {
|
|
172
|
+
await response.body?.cancel();
|
|
173
|
+
} catch {
|
|
174
|
+
}
|
|
175
|
+
const delayMs = pickRetryDelayMs(attempt, retryPolicy);
|
|
176
|
+
await sleep(delayMs, context.signal);
|
|
177
|
+
}
|
|
178
|
+
if (!response || !response.ok) {
|
|
179
|
+
throw new BackendTransportError(kind, `chat backend returned ${lastStatus || "unknown"}`, {
|
|
180
|
+
status: lastStatus || 0
|
|
136
181
|
});
|
|
137
182
|
}
|
|
138
183
|
yield* streamResponseEvents(response, context);
|