@kici-dev/agent 0.4.0 → 0.5.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/execution/download.d.ts +27 -2
- package/dist/execution/generator-context.d.ts +54 -0
- package/dist/execution/global-eval-runner.d.ts +92 -0
- package/dist/execution/global-workflow-env.d.ts +57 -0
- package/dist/execution/init-runner.d.ts +60 -3
- package/dist/execution/job-runner.d.ts +98 -0
- package/dist/execution/sandbox/step-loop.d.ts +10 -1
- package/dist/execution/sandbox/workflow-runner.d.ts +52 -1
- package/dist/execution/workflow-loader.d.ts +8 -1
- package/dist/index.js +89 -19
- package/dist/metrics/prometheus.d.ts +10 -10
- package/dist/server.js +1155 -158
- package/dist/workflow-runner-bundle.js +5052 -4591
- package/dist/workflow-runner.js +269 -67
- package/package.json +5 -5
- package/sbom.spdx.json +69 -64
package/dist/index.js
CHANGED
|
@@ -748,7 +748,7 @@ function isAbsoluteRel(rel) {
|
|
|
748
748
|
* env vars — the install runs with `--ignore-scripts` whenever a private
|
|
749
749
|
* registry is configured.
|
|
750
750
|
*/
|
|
751
|
-
const logger$
|
|
751
|
+
const logger$3 = createLogger({ prefix: "dep-installer" });
|
|
752
752
|
const execFileAsync = promisify(execFile);
|
|
753
753
|
/** Install subprocess timeout (10 min) and stdout/stderr buffer (128 MiB). */
|
|
754
754
|
const INSTALL_TIMEOUT_MS = 6e5;
|
|
@@ -793,7 +793,7 @@ async function installDeps(kiciDir, opts = {}) {
|
|
|
793
793
|
const repoRoot = opts.repoRoot ?? dirname(kiciDir);
|
|
794
794
|
const packageManager = await detectKiciPackageManager(repoRoot, kiciDir);
|
|
795
795
|
const yarnFlavor = packageManager === PackageManager.Yarn ? await detectKiciYarnFlavor(repoRoot, kiciDir) : YarnFlavor.Classic;
|
|
796
|
-
logger$
|
|
796
|
+
logger$3.info("Installing deps inline", {
|
|
797
797
|
packageManager,
|
|
798
798
|
yarnFlavor,
|
|
799
799
|
dir: kiciDir
|
|
@@ -851,7 +851,7 @@ async function installDeps(kiciDir, opts = {}) {
|
|
|
851
851
|
if (packageManager === PackageManager.Yarn) await buildYarnWorkspaceClosure(repoRoot, kiciDir, yarnFlavor);
|
|
852
852
|
const durationMs = Date.now() - startTime;
|
|
853
853
|
process.stderr.write(`[dep-installer:trace] install complete: ${durationMs}ms\n`);
|
|
854
|
-
logger$
|
|
854
|
+
logger$3.info("Deps installed inline", {
|
|
855
855
|
packageManager,
|
|
856
856
|
durationMs
|
|
857
857
|
});
|
|
@@ -1143,10 +1143,25 @@ var init_dep_restore = __esmMin((() => {
|
|
|
1143
1143
|
* dep-restore.ts and workflow-loader.ts.
|
|
1144
1144
|
*/
|
|
1145
1145
|
var download_exports = /* @__PURE__ */ __exportAll({
|
|
1146
|
+
UPLOAD_MAX_RETRIES: () => 2,
|
|
1146
1147
|
downloadUrl: () => downloadUrl,
|
|
1147
1148
|
uploadToPresignedUrl: () => uploadToPresignedUrl
|
|
1148
1149
|
});
|
|
1149
1150
|
/**
|
|
1151
|
+
* Whether a failed upload attempt is worth repeating.
|
|
1152
|
+
*
|
|
1153
|
+
* A transport failure (connection refused, reset, DNS) never reached a
|
|
1154
|
+
* responder, and 5xx / 429 are the object-storage overload signals AWS
|
|
1155
|
+
* documents as retry-with-backoff (S3 answers `SlowDown` with 503). Every other
|
|
1156
|
+
* status is a decision the server will repeat: a 403 from an expired or
|
|
1157
|
+
* malformed signature, a 400 from a malformed request. Retrying those burns the
|
|
1158
|
+
* ceiling without a chance of success and delays the real error.
|
|
1159
|
+
*/
|
|
1160
|
+
function isRetryableUploadFailure(err) {
|
|
1161
|
+
if (!(err instanceof PresignedUploadHttpError)) return true;
|
|
1162
|
+
return err.statusCode >= 500 || err.statusCode === 429;
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1150
1165
|
* Download content from an HTTP/HTTPS URL.
|
|
1151
1166
|
*
|
|
1152
1167
|
* Includes a 5-minute timeout to prevent the agent from hanging indefinitely
|
|
@@ -1170,21 +1185,10 @@ function downloadUrl(url) {
|
|
|
1170
1185
|
}).on("error", reject);
|
|
1171
1186
|
});
|
|
1172
1187
|
}
|
|
1173
|
-
/**
|
|
1174
|
-
|
|
1175
|
-
*
|
|
1176
|
-
* Used for direct-to-S3 uploads of bundles and dep tarballs. Localhost /
|
|
1177
|
-
* 127.0.0.1 URLs are rewritten via `resolveOrchestratorUrl` so the
|
|
1178
|
-
* filesystem cache backend's signed URLs work from container agents that
|
|
1179
|
-
* can't reach the orchestrator's host loopback directly.
|
|
1180
|
-
*
|
|
1181
|
-
* @param url - The pre-signed URL to upload to
|
|
1182
|
-
* @param data - The buffer to upload
|
|
1183
|
-
*/
|
|
1184
|
-
function uploadToPresignedUrl(url, data) {
|
|
1188
|
+
/** One PUT of the whole buffer. Rejects with {@link PresignedUploadHttpError} on a non-2xx. */
|
|
1189
|
+
function putOnce(resolvedUrl, data, timeoutMs) {
|
|
1185
1190
|
return new Promise((resolve, reject) => {
|
|
1186
|
-
const
|
|
1187
|
-
const parsed = new URL(resolved);
|
|
1191
|
+
const parsed = new URL(resolvedUrl);
|
|
1188
1192
|
const req = (parsed.protocol === "https:" ? https : http).request({
|
|
1189
1193
|
hostname: parsed.hostname,
|
|
1190
1194
|
port: parsed.port,
|
|
@@ -1193,7 +1197,7 @@ function uploadToPresignedUrl(url, data) {
|
|
|
1193
1197
|
headers: { "Content-Length": data.length }
|
|
1194
1198
|
}, (res) => {
|
|
1195
1199
|
if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) {
|
|
1196
|
-
reject(
|
|
1200
|
+
reject(new PresignedUploadHttpError(res.statusCode));
|
|
1197
1201
|
res.resume();
|
|
1198
1202
|
return;
|
|
1199
1203
|
}
|
|
@@ -1201,14 +1205,80 @@ function uploadToPresignedUrl(url, data) {
|
|
|
1201
1205
|
res.on("end", () => resolve());
|
|
1202
1206
|
res.on("error", reject);
|
|
1203
1207
|
});
|
|
1208
|
+
req.setTimeout(timeoutMs, () => {
|
|
1209
|
+
req.destroy(/* @__PURE__ */ new Error(`Pre-signed upload timed out after ${timeoutMs}ms`));
|
|
1210
|
+
});
|
|
1204
1211
|
req.on("error", reject);
|
|
1205
1212
|
req.end(data);
|
|
1206
1213
|
});
|
|
1207
1214
|
}
|
|
1208
|
-
|
|
1215
|
+
/**
|
|
1216
|
+
* Upload a buffer to a pre-signed S3 URL via HTTP PUT, retrying a transient
|
|
1217
|
+
* failure.
|
|
1218
|
+
*
|
|
1219
|
+
* Used for direct-to-S3 uploads of bundles and dep tarballs. Localhost /
|
|
1220
|
+
* 127.0.0.1 URLs are rewritten via `resolveOrchestratorUrl` so the
|
|
1221
|
+
* filesystem cache backend's signed URLs work from container agents that
|
|
1222
|
+
* can't reach the orchestrator's host loopback directly.
|
|
1223
|
+
*
|
|
1224
|
+
* **Why retrying is safe here.** A pre-signed PUT writes one whole object at a
|
|
1225
|
+
* single key: there is no multipart session, no append, and no
|
|
1226
|
+
* server-generated identity, so a repeat attempt writes the same bytes to the
|
|
1227
|
+
* same key and the last write wins. S3 also only makes an object visible once
|
|
1228
|
+
* the body has been received in full, so an attempt that died mid-body left
|
|
1229
|
+
* nothing behind. A retry therefore cannot double-write or produce a torn
|
|
1230
|
+
* object — which is why every AWS SDK retries PUTs by default.
|
|
1231
|
+
*
|
|
1232
|
+
* Only a failure that can plausibly differ next time is repeated — see
|
|
1233
|
+
* {@link isRetryableUploadFailure}.
|
|
1234
|
+
*
|
|
1235
|
+
* @param url - The pre-signed URL to upload to
|
|
1236
|
+
* @param data - The buffer to upload
|
|
1237
|
+
* @param opts.baseDelayMs - Backoff before the first retry (doubles thereafter)
|
|
1238
|
+
* @param opts.timeoutMs - Per-attempt socket-inactivity timeout (see
|
|
1239
|
+
* {@link UPLOAD_TIMEOUT_MS}); an override exists so a test can drive the
|
|
1240
|
+
* stall path without waiting out the production budget.
|
|
1241
|
+
*/
|
|
1242
|
+
async function uploadToPresignedUrl(url, data, opts) {
|
|
1243
|
+
const resolved = resolveOrchestratorUrl(url);
|
|
1244
|
+
const baseDelayMs = opts?.baseDelayMs ?? UPLOAD_RETRY_BASE_DELAY_MS;
|
|
1245
|
+
const timeoutMs = opts?.timeoutMs ?? UPLOAD_TIMEOUT_MS;
|
|
1246
|
+
let lastError;
|
|
1247
|
+
for (let attempt = 0; attempt <= 2; attempt++) {
|
|
1248
|
+
if (attempt > 0) {
|
|
1249
|
+
const delayMs = baseDelayMs * 2 ** (attempt - 1);
|
|
1250
|
+
logger$1.warn("Retrying pre-signed upload", {
|
|
1251
|
+
attempt,
|
|
1252
|
+
delayMs,
|
|
1253
|
+
error: lastError?.message
|
|
1254
|
+
});
|
|
1255
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
1256
|
+
}
|
|
1257
|
+
try {
|
|
1258
|
+
await putOnce(resolved, data, timeoutMs);
|
|
1259
|
+
return;
|
|
1260
|
+
} catch (err) {
|
|
1261
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
1262
|
+
if (!isRetryableUploadFailure(lastError)) throw lastError;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
throw new Error(`Pre-signed upload failed after 3 attempts: ${lastError?.message}`);
|
|
1266
|
+
}
|
|
1267
|
+
var logger$1, DOWNLOAD_TIMEOUT_MS$1, UPLOAD_TIMEOUT_MS, UPLOAD_RETRY_BASE_DELAY_MS, PresignedUploadHttpError;
|
|
1209
1268
|
var init_download = __esmMin((() => {
|
|
1210
1269
|
init_dep_restore();
|
|
1270
|
+
logger$1 = createLogger({ prefix: "agent:download" });
|
|
1211
1271
|
DOWNLOAD_TIMEOUT_MS$1 = 300 * 1e3;
|
|
1272
|
+
UPLOAD_TIMEOUT_MS = 300 * 1e3;
|
|
1273
|
+
UPLOAD_RETRY_BASE_DELAY_MS = 500;
|
|
1274
|
+
PresignedUploadHttpError = class extends Error {
|
|
1275
|
+
statusCode;
|
|
1276
|
+
constructor(statusCode) {
|
|
1277
|
+
super(`HTTP ${statusCode} uploading to pre-signed URL`);
|
|
1278
|
+
this.statusCode = statusCode;
|
|
1279
|
+
this.name = "PresignedUploadHttpError";
|
|
1280
|
+
}
|
|
1281
|
+
};
|
|
1212
1282
|
}));
|
|
1213
1283
|
//#endregion
|
|
1214
1284
|
//#region src/execution/cache/cache-engine.ts
|
|
@@ -2,40 +2,40 @@
|
|
|
2
2
|
* Total completed jobs.
|
|
3
3
|
* Labels:
|
|
4
4
|
* - status: success | failed | cancelled
|
|
5
|
-
* - scaler: injected by orch-side AgentMetricsAggregator
|
|
5
|
+
* - scaler: injected by orch-side AgentMetricsAggregator; `stateful` for static agents, backend type (`container` / `firecracker` / `bare-metal`) for scaler-managed
|
|
6
6
|
*/
|
|
7
7
|
export declare const jobsTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
8
8
|
/**
|
|
9
9
|
* Currently running jobs.
|
|
10
10
|
* Labels:
|
|
11
|
-
* - scaler: injected by orch-side AgentMetricsAggregator
|
|
11
|
+
* - scaler: injected by orch-side AgentMetricsAggregator; `stateful` for static agents, backend type (`container` / `firecracker` / `bare-metal`) for scaler-managed
|
|
12
12
|
*/
|
|
13
13
|
export declare const jobsActive: import("@opentelemetry/api").UpDownCounter<import("@opentelemetry/api").Attributes>;
|
|
14
14
|
/**
|
|
15
15
|
* Total completed steps.
|
|
16
16
|
* Labels:
|
|
17
17
|
* - status: success | failed | skipped
|
|
18
|
-
* - scaler: injected by orch-side AgentMetricsAggregator
|
|
18
|
+
* - scaler: injected by orch-side AgentMetricsAggregator; `stateful` for static agents, backend type (`container` / `firecracker` / `bare-metal`) for scaler-managed
|
|
19
19
|
*/
|
|
20
20
|
export declare const stepsTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
21
21
|
/**
|
|
22
22
|
* Step execution duration in seconds.
|
|
23
23
|
* Advisory boundaries cover sub-second steps through 30-minute long-running steps.
|
|
24
24
|
* Labels:
|
|
25
|
-
* - scaler: injected by orch-side AgentMetricsAggregator
|
|
25
|
+
* - scaler: injected by orch-side AgentMetricsAggregator; `stateful` for static agents, backend type (`container` / `firecracker` / `bare-metal`) for scaler-managed
|
|
26
26
|
*/
|
|
27
27
|
export declare const stepDurationSeconds: import("@opentelemetry/api").Histogram<import("@opentelemetry/api").Attributes>;
|
|
28
28
|
/**
|
|
29
29
|
* Git clone duration in seconds.
|
|
30
30
|
* Advisory boundaries cover fast shallow clones through large repo clones.
|
|
31
31
|
* Labels:
|
|
32
|
-
* - scaler: injected by orch-side AgentMetricsAggregator
|
|
32
|
+
* - scaler: injected by orch-side AgentMetricsAggregator; `stateful` for static agents, backend type (`container` / `firecracker` / `bare-metal`) for scaler-managed
|
|
33
33
|
*/
|
|
34
34
|
export declare const cloneDurationSeconds: import("@opentelemetry/api").Histogram<import("@opentelemetry/api").Attributes>;
|
|
35
35
|
/**
|
|
36
36
|
* Total log bytes streamed back to orchestrator.
|
|
37
37
|
* Labels:
|
|
38
|
-
* - scaler: injected by orch-side AgentMetricsAggregator
|
|
38
|
+
* - scaler: injected by orch-side AgentMetricsAggregator; `stateful` for static agents, backend type (`container` / `firecracker` / `bare-metal`) for scaler-managed
|
|
39
39
|
*/
|
|
40
40
|
export declare const logBytesTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
41
41
|
/**
|
|
@@ -51,7 +51,7 @@ export declare const logBytesTotal: import("@opentelemetry/api").Counter<import(
|
|
|
51
51
|
* Labels:
|
|
52
52
|
* - mode: `pause` (producer paused, no data loss) | `drop` (lines
|
|
53
53
|
* discarded with a `[N lines dropped due to backpressure]` marker)
|
|
54
|
-
* - scaler: injected by orch-side AgentMetricsAggregator
|
|
54
|
+
* - scaler: injected by orch-side AgentMetricsAggregator; `stateful` for static agents, backend type (`container` / `firecracker` / `bare-metal`) for scaler-managed
|
|
55
55
|
*/
|
|
56
56
|
export declare const logBackpressureEventsTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
57
57
|
/**
|
|
@@ -64,7 +64,7 @@ export declare const logBackpressureEventsTotal: import("@opentelemetry/api").Co
|
|
|
64
64
|
* producer.
|
|
65
65
|
*
|
|
66
66
|
* Labels:
|
|
67
|
-
* - scaler: injected by orch-side AgentMetricsAggregator
|
|
67
|
+
* - scaler: injected by orch-side AgentMetricsAggregator; `stateful` for static agents, backend type (`container` / `firecracker` / `bare-metal`) for scaler-managed
|
|
68
68
|
*/
|
|
69
69
|
export declare const logLinesDroppedTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
70
70
|
/**
|
|
@@ -81,7 +81,7 @@ export declare const logLinesDroppedTotal: import("@opentelemetry/api").Counter<
|
|
|
81
81
|
*
|
|
82
82
|
* Labels:
|
|
83
83
|
* - mode: `pause` | `drop`
|
|
84
|
-
* - scaler: injected by orch-side AgentMetricsAggregator
|
|
84
|
+
* - scaler: injected by orch-side AgentMetricsAggregator; `stateful` for static agents, backend type (`container` / `firecracker` / `bare-metal`) for scaler-managed
|
|
85
85
|
*/
|
|
86
86
|
export declare const logBackpressureActive: import("@opentelemetry/api").UpDownCounter<import("@opentelemetry/api").Attributes>;
|
|
87
87
|
/**
|
|
@@ -89,7 +89,7 @@ export declare const logBackpressureActive: import("@opentelemetry/api").UpDownC
|
|
|
89
89
|
* Use add(1) for connected, add(-1) for disconnected.
|
|
90
90
|
*
|
|
91
91
|
* Labels:
|
|
92
|
-
* - scaler: injected by orch-side AgentMetricsAggregator
|
|
92
|
+
* - scaler: injected by orch-side AgentMetricsAggregator; `stateful` for static agents, backend type (`container` / `firecracker` / `bare-metal`) for scaler-managed
|
|
93
93
|
*/
|
|
94
94
|
export declare const connectionStatus: import("@opentelemetry/api").UpDownCounter<import("@opentelemetry/api").Attributes>;
|
|
95
95
|
//# sourceMappingURL=prometheus.d.ts.map
|