rudel 0.1.16 → 0.1.17
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/cli.js +53 -8
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1889,7 +1889,7 @@ async function run(app, inputs, context) {
|
|
|
1889
1889
|
// package.json
|
|
1890
1890
|
var package_default = {
|
|
1891
1891
|
name: "rudel",
|
|
1892
|
-
version: "0.1.
|
|
1892
|
+
version: "0.1.17",
|
|
1893
1893
|
type: "module",
|
|
1894
1894
|
description: "CLI for the Coding Agent Analytics Platform rudel.ai",
|
|
1895
1895
|
license: "MIT",
|
|
@@ -1924,7 +1924,7 @@ var package_default = {
|
|
|
1924
1924
|
build: "bun build src/bin/cli.ts --outdir dist --target node",
|
|
1925
1925
|
prepack: "bun run build",
|
|
1926
1926
|
test: "bun test",
|
|
1927
|
-
"test:integration": "bun test ./src/__tests__/api-upload.integration.ts ./src/__tests__/auth-verify.integration.ts ./src/__tests__/auth.e2e.integration.ts"
|
|
1927
|
+
"test:integration": "bun test ./src/__tests__/api-upload.integration.ts ./src/__tests__/uploader-rate-limit.integration.ts ./src/__tests__/auth-verify.integration.ts ./src/__tests__/auth.e2e.integration.ts"
|
|
1928
1928
|
},
|
|
1929
1929
|
dependencies: {
|
|
1930
1930
|
"@clack/prompts": "^1.0.1",
|
|
@@ -6385,7 +6385,7 @@ class ClaudeCodeAdapter {
|
|
|
6385
6385
|
await ingestRudelClaudeSessions(ingestor, [row]);
|
|
6386
6386
|
}
|
|
6387
6387
|
buildRow(input, context) {
|
|
6388
|
-
const now =
|
|
6388
|
+
const now = context.ingestedAt.toISOString().replace("Z", "");
|
|
6389
6389
|
const subagents = {};
|
|
6390
6390
|
if (input.subagents) {
|
|
6391
6391
|
for (const sub of input.subagents) {
|
|
@@ -7717,7 +7717,7 @@ class CodexAdapter {
|
|
|
7717
7717
|
await ingestRudelCodexSessions(ingestor, [row]);
|
|
7718
7718
|
}
|
|
7719
7719
|
buildRow(input, context) {
|
|
7720
|
-
const now =
|
|
7720
|
+
const now = context.ingestedAt.toISOString().replace("Z", "");
|
|
7721
7721
|
const timestamps = this.extractTimestamps(input.content);
|
|
7722
7722
|
return {
|
|
7723
7723
|
session_date: timestamps ? toClickHouseDateTime(timestamps.sessionDate) : now,
|
|
@@ -13157,9 +13157,18 @@ var SessionTagSchema = exports_external.enum([
|
|
|
13157
13157
|
"tests",
|
|
13158
13158
|
"other"
|
|
13159
13159
|
]);
|
|
13160
|
+
var INGEST_AGGREGATE_CONTENT_MAX_BYTES = 128 * 1024 * 1024;
|
|
13161
|
+
var INGEST_MAX_SUBAGENT_COUNT = 512;
|
|
13162
|
+
var INGEST_LIMIT_REASONS = {
|
|
13163
|
+
requestLimit: "request_limit",
|
|
13164
|
+
byteLimit: "byte_limit",
|
|
13165
|
+
sessionLimit: "session_limit",
|
|
13166
|
+
transcriptTooLarge: "transcript_too_large"
|
|
13167
|
+
};
|
|
13168
|
+
var INGEST_CONTENT_MAX_CODE_UNITS = 160 * 1024 * 1024;
|
|
13160
13169
|
var SubagentFileSchema = exports_external.object({
|
|
13161
|
-
agentId: exports_external.string(),
|
|
13162
|
-
content: exports_external.string()
|
|
13170
|
+
agentId: exports_external.string().max(200),
|
|
13171
|
+
content: exports_external.string().max(INGEST_CONTENT_MAX_CODE_UNITS)
|
|
13163
13172
|
});
|
|
13164
13173
|
var IngestSessionInputSchema = exports_external.object({
|
|
13165
13174
|
source: SourceSchema.default("claude_code"),
|
|
@@ -13171,8 +13180,8 @@ var IngestSessionInputSchema = exports_external.object({
|
|
|
13171
13180
|
gitBranch: exports_external.string().max(200).optional(),
|
|
13172
13181
|
gitSha: exports_external.string().max(200).optional(),
|
|
13173
13182
|
tag: SessionTagSchema.optional(),
|
|
13174
|
-
content: exports_external.string(),
|
|
13175
|
-
subagents: exports_external.array(SubagentFileSchema).optional(),
|
|
13183
|
+
content: exports_external.string().max(INGEST_CONTENT_MAX_CODE_UNITS),
|
|
13184
|
+
subagents: exports_external.array(SubagentFileSchema).max(INGEST_MAX_SUBAGENT_COUNT).refine((subagents) => new Set(subagents.map((subagent) => subagent.agentId)).size === subagents.length, { message: "Subagent agentId values must be unique" }).optional(),
|
|
13176
13185
|
organizationId: exports_external.string().max(200).optional(),
|
|
13177
13186
|
client_surface: ProductAnalyticsClientSurfaceSchema.optional(),
|
|
13178
13187
|
upload_mode: ProductAnalyticsUploadModeSchema.optional(),
|
|
@@ -18214,6 +18223,13 @@ function formatUploadError(error) {
|
|
|
18214
18223
|
}
|
|
18215
18224
|
if (isRateLimited(error)) {
|
|
18216
18225
|
const data = getErrorData(error);
|
|
18226
|
+
const isRequestLimit = data.reason === INGEST_LIMIT_REASONS.requestLimit;
|
|
18227
|
+
if (isRequestLimit || data.reason === INGEST_LIMIT_REASONS.byteLimit) {
|
|
18228
|
+
const limit2 = data.limit === null ? null : isRequestLimit ? `${data.limit} requests` : `${formatMebibytes(data.limit)} MiB`;
|
|
18229
|
+
const detail = limit2 && data.windowSeconds ? ` (${limit2} per ${Math.round(data.windowSeconds / 60)} min)` : "";
|
|
18230
|
+
const kind = isRequestLimit ? "request" : "byte";
|
|
18231
|
+
return `Ingest ${kind} limit reached${detail}. Wait and retry with: rudel upload --retry`;
|
|
18232
|
+
}
|
|
18217
18233
|
const windowMin = data?.windowSeconds ? Math.round(data.windowSeconds / 60) : 60;
|
|
18218
18234
|
const limit = data?.limit ?? "unknown";
|
|
18219
18235
|
return `Rate limit reached (${limit} sessions per ${windowMin} min). Wait and retry with: rudel upload --retry`;
|
|
@@ -18222,6 +18238,10 @@ function formatUploadError(error) {
|
|
|
18222
18238
|
return "This session ID is already owned by another organization member. Upload it from the original member account or use a different session ID.";
|
|
18223
18239
|
}
|
|
18224
18240
|
if (isPayloadTooLarge(error)) {
|
|
18241
|
+
const data = getErrorData(error);
|
|
18242
|
+
if (data.reason === INGEST_LIMIT_REASONS.transcriptTooLarge) {
|
|
18243
|
+
return formatTranscriptTooLargeError(data.actualBytes, data.maxBytes);
|
|
18244
|
+
}
|
|
18225
18245
|
return formatPayloadTooLargeError(error);
|
|
18226
18246
|
}
|
|
18227
18247
|
if (isServerError(error)) {
|
|
@@ -18261,8 +18281,10 @@ function getErrorData(error) {
|
|
|
18261
18281
|
const data = isRecord(error.data) ? error.data : null;
|
|
18262
18282
|
return {
|
|
18263
18283
|
authMessage: getStringField(data, "authMessage"),
|
|
18284
|
+
actualBytes: getNumberField(data, "actualBytes"),
|
|
18264
18285
|
code: getStringField(data, "code"),
|
|
18265
18286
|
limit: getNumberField(data, "limit"),
|
|
18287
|
+
maxBytes: getNumberField(data, "maxBytes"),
|
|
18266
18288
|
reason: getStringField(data, "reason"),
|
|
18267
18289
|
tryAgainIn: getNumberField(data, "tryAgainIn"),
|
|
18268
18290
|
windowSeconds: getNumberField(data, "windowSeconds")
|
|
@@ -18292,6 +18314,15 @@ function formatWait(milliseconds) {
|
|
|
18292
18314
|
return `${hours} hr`;
|
|
18293
18315
|
}
|
|
18294
18316
|
async function uploadSession(request, config) {
|
|
18317
|
+
const maxAggregateBytes = config.maxAggregateBytes ?? INGEST_AGGREGATE_CONTENT_MAX_BYTES;
|
|
18318
|
+
const aggregateBytes = getUploadAggregateBytes(request);
|
|
18319
|
+
if (aggregateBytes > maxAggregateBytes) {
|
|
18320
|
+
return {
|
|
18321
|
+
success: false,
|
|
18322
|
+
error: formatTranscriptTooLargeError(aggregateBytes, maxAggregateBytes),
|
|
18323
|
+
attempts: 0
|
|
18324
|
+
};
|
|
18325
|
+
}
|
|
18295
18326
|
const link = new RPCLink({
|
|
18296
18327
|
url: config.endpoint,
|
|
18297
18328
|
headers: config.authType === "api-key" ? { "x-api-key": config.token } : { Authorization: `Bearer ${config.token}` }
|
|
@@ -18330,6 +18361,20 @@ async function uploadSession(request, config) {
|
|
|
18330
18361
|
attempts: MAX_ATTEMPTS
|
|
18331
18362
|
};
|
|
18332
18363
|
}
|
|
18364
|
+
function getUploadAggregateBytes(request) {
|
|
18365
|
+
return Buffer.byteLength(request.content, "utf8") + (request.subagents ?? []).reduce((total, subagent) => total + Buffer.byteLength(subagent.content, "utf8"), 0);
|
|
18366
|
+
}
|
|
18367
|
+
function formatTranscriptTooLargeError(actualBytes, maxBytes) {
|
|
18368
|
+
if (actualBytes === null || maxBytes === null) {
|
|
18369
|
+
return "Session transcript payload exceeds the per-session limit. Reduce the transcript/subagent payload before retrying.";
|
|
18370
|
+
}
|
|
18371
|
+
const actualText = `${formatMebibytes(actualBytes)} MiB`;
|
|
18372
|
+
const limitText = `the ${formatMebibytes(maxBytes)} MiB per-session limit`;
|
|
18373
|
+
return `Session transcript payload is ${actualText}, above ${limitText}. Reduce the transcript/subagent payload before retrying.`;
|
|
18374
|
+
}
|
|
18375
|
+
function formatMebibytes(bytes) {
|
|
18376
|
+
return (bytes / (1024 * 1024)).toFixed(2);
|
|
18377
|
+
}
|
|
18333
18378
|
|
|
18334
18379
|
// src/commands/enable.ts
|
|
18335
18380
|
async function runEnable() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rudel",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for the Coding Agent Analytics Platform rudel.ai",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"build": "bun build src/bin/cli.ts --outdir dist --target node",
|
|
36
36
|
"prepack": "bun run build",
|
|
37
37
|
"test": "bun test",
|
|
38
|
-
"test:integration": "bun test ./src/__tests__/api-upload.integration.ts ./src/__tests__/auth-verify.integration.ts ./src/__tests__/auth.e2e.integration.ts"
|
|
38
|
+
"test:integration": "bun test ./src/__tests__/api-upload.integration.ts ./src/__tests__/uploader-rate-limit.integration.ts ./src/__tests__/auth-verify.integration.ts ./src/__tests__/auth.e2e.integration.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@clack/prompts": "^1.0.1",
|