@compaction/cli 0.1.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/LICENSE +663 -0
- package/README.md +319 -0
- package/dist/cli/commands/adapter.d.ts +2 -0
- package/dist/cli/commands/adapter.js +49 -0
- package/dist/cli/commands/aggregate.d.ts +2 -0
- package/dist/cli/commands/aggregate.js +60 -0
- package/dist/cli/commands/analyze.d.ts +2 -0
- package/dist/cli/commands/analyze.js +55 -0
- package/dist/cli/commands/apply-context.d.ts +12 -0
- package/dist/cli/commands/apply-context.js +80 -0
- package/dist/cli/commands/apply.d.ts +2 -0
- package/dist/cli/commands/apply.js +65 -0
- package/dist/cli/commands/approve.d.ts +2 -0
- package/dist/cli/commands/approve.js +55 -0
- package/dist/cli/commands/audit.d.ts +2 -0
- package/dist/cli/commands/audit.js +63 -0
- package/dist/cli/commands/billing-delta.d.ts +2 -0
- package/dist/cli/commands/billing-delta.js +246 -0
- package/dist/cli/commands/capture-claude-code.d.ts +19 -0
- package/dist/cli/commands/capture-claude-code.js +198 -0
- package/dist/cli/commands/capture-provider-usage.d.ts +35 -0
- package/dist/cli/commands/capture-provider-usage.js +113 -0
- package/dist/cli/commands/capture.d.ts +2 -0
- package/dist/cli/commands/capture.js +76 -0
- package/dist/cli/commands/compact.d.ts +2 -0
- package/dist/cli/commands/compact.js +206 -0
- package/dist/cli/commands/eval.d.ts +2 -0
- package/dist/cli/commands/eval.js +66 -0
- package/dist/cli/commands/export-session-seed.d.ts +11 -0
- package/dist/cli/commands/export-session-seed.js +42 -0
- package/dist/cli/commands/feedback.d.ts +2 -0
- package/dist/cli/commands/feedback.js +233 -0
- package/dist/cli/commands/import.d.ts +2 -0
- package/dist/cli/commands/import.js +60 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.js +216 -0
- package/dist/cli/commands/integrations.d.ts +2 -0
- package/dist/cli/commands/integrations.js +29 -0
- package/dist/cli/commands/launch-treatment-session.d.ts +14 -0
- package/dist/cli/commands/launch-treatment-session.js +50 -0
- package/dist/cli/commands/optimize.d.ts +2 -0
- package/dist/cli/commands/optimize.js +33 -0
- package/dist/cli/commands/recommend.d.ts +4 -0
- package/dist/cli/commands/recommend.js +66 -0
- package/dist/cli/commands/review.d.ts +2 -0
- package/dist/cli/commands/review.js +60 -0
- package/dist/cli/commands/run.d.ts +2 -0
- package/dist/cli/commands/run.js +49 -0
- package/dist/cli/commands/spend.d.ts +2 -0
- package/dist/cli/commands/spend.js +24 -0
- package/dist/cli/commands/summary.d.ts +2 -0
- package/dist/cli/commands/summary.js +19 -0
- package/dist/cli/engine-degrade.d.ts +40 -0
- package/dist/cli/engine-degrade.js +59 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +59 -0
- package/dist/core/adapter-validation.d.ts +32 -0
- package/dist/core/adapter-validation.js +185 -0
- package/dist/core/adapters/claude-code-adapter.d.ts +51 -0
- package/dist/core/adapters/claude-code-adapter.js +539 -0
- package/dist/core/adapters/claude-code-discovery.d.ts +40 -0
- package/dist/core/adapters/claude-code-discovery.js +100 -0
- package/dist/core/aggregate-format.d.ts +62 -0
- package/dist/core/aggregate-format.js +349 -0
- package/dist/core/api-client/client.d.ts +43 -0
- package/dist/core/api-client/client.js +143 -0
- package/dist/core/api-client/config.d.ts +36 -0
- package/dist/core/api-client/config.js +44 -0
- package/dist/core/api-client/index.d.ts +13 -0
- package/dist/core/api-client/index.js +14 -0
- package/dist/core/api-client/payload.d.ts +93 -0
- package/dist/core/api-client/payload.js +180 -0
- package/dist/core/api-client/types.d.ts +95 -0
- package/dist/core/api-client/types.js +21 -0
- package/dist/core/artifact-writer.d.ts +2 -0
- package/dist/core/artifact-writer.js +14 -0
- package/dist/core/audit-report.d.ts +91 -0
- package/dist/core/audit-report.js +422 -0
- package/dist/core/billing-delta/billing-delta-record.d.ts +290 -0
- package/dist/core/billing-delta/billing-delta-record.js +394 -0
- package/dist/core/capture-adapter.d.ts +74 -0
- package/dist/core/capture-adapter.js +2 -0
- package/dist/core/command-runner.d.ts +29 -0
- package/dist/core/command-runner.js +96 -0
- package/dist/core/content-hash.d.ts +1 -0
- package/dist/core/content-hash.js +5 -0
- package/dist/core/cost-calculator.d.ts +6 -0
- package/dist/core/cost-calculator.js +20 -0
- package/dist/core/feedback-bundle.d.ts +159 -0
- package/dist/core/feedback-bundle.js +406 -0
- package/dist/core/openai-agents-capture.d.ts +66 -0
- package/dist/core/openai-agents-capture.js +475 -0
- package/dist/core/policy-types.d.ts +85 -0
- package/dist/core/policy-types.js +29 -0
- package/dist/core/pricing.d.ts +23 -0
- package/dist/core/pricing.js +55 -0
- package/dist/core/provider-usage/credential-redaction.d.ts +23 -0
- package/dist/core/provider-usage/credential-redaction.js +60 -0
- package/dist/core/provider-usage/provider-usage-adapter.d.ts +65 -0
- package/dist/core/provider-usage/provider-usage-adapter.js +147 -0
- package/dist/core/provider-usage/provider-usage-client.d.ts +89 -0
- package/dist/core/provider-usage/provider-usage-client.js +96 -0
- package/dist/core/report-generator.d.ts +7 -0
- package/dist/core/report-generator.js +275 -0
- package/dist/core/run-aggregator.d.ts +50 -0
- package/dist/core/run-aggregator.js +251 -0
- package/dist/core/run-labels.d.ts +52 -0
- package/dist/core/run-labels.js +80 -0
- package/dist/core/run-trace-converter.d.ts +3 -0
- package/dist/core/run-trace-converter.js +94 -0
- package/dist/core/safety-report.d.ts +52 -0
- package/dist/core/safety-report.js +440 -0
- package/dist/core/savings.d.ts +22 -0
- package/dist/core/savings.js +36 -0
- package/dist/core/session-aggregate.d.ts +211 -0
- package/dist/core/session-aggregate.js +490 -0
- package/dist/core/skill-injection-detector.d.ts +51 -0
- package/dist/core/skill-injection-detector.js +146 -0
- package/dist/core/spend-attribution.d.ts +169 -0
- package/dist/core/spend-attribution.js +611 -0
- package/dist/core/standalone-capsule-provenance.d.ts +4 -0
- package/dist/core/standalone-capsule-provenance.js +62 -0
- package/dist/core/state-capsule.d.ts +3 -0
- package/dist/core/state-capsule.js +147 -0
- package/dist/core/token-accounting.d.ts +62 -0
- package/dist/core/token-accounting.js +81 -0
- package/dist/core/token-estimator.d.ts +3 -0
- package/dist/core/token-estimator.js +18 -0
- package/dist/core/trace-adapters.d.ts +53 -0
- package/dist/core/trace-adapters.js +714 -0
- package/dist/core/trace-fingerprint.d.ts +79 -0
- package/dist/core/trace-fingerprint.js +102 -0
- package/dist/core/trace-intake.d.ts +41 -0
- package/dist/core/trace-intake.js +164 -0
- package/dist/core/trace-parser.d.ts +203 -0
- package/dist/core/trace-parser.js +143 -0
- package/dist/core/types.d.ts +238 -0
- package/dist/core/types.js +2 -0
- package/dist/core/usage-metadata.d.ts +51 -0
- package/dist/core/usage-metadata.js +122 -0
- package/dist/core/waste-detector.d.ts +8 -0
- package/dist/core/waste-detector.js +58 -0
- package/package.json +90 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { AgentTrace } from "./types.js";
|
|
2
|
+
/** Algorithm identifier surfaced alongside the digest so the signal is self-describing. */
|
|
3
|
+
export declare const TRACE_FINGERPRINT_ALGORITHM = "sha256-canonical-content-v1";
|
|
4
|
+
/**
|
|
5
|
+
* A non-sensitive per-run distinctness fingerprint for a captured trace.
|
|
6
|
+
*
|
|
7
|
+
* Every field here is non-sensitive: a hex digest plus structural counts. There is
|
|
8
|
+
* NO message/prompt/tool-output text in this object.
|
|
9
|
+
*/
|
|
10
|
+
export interface TraceFingerprint {
|
|
11
|
+
/** Algorithm + canonicalization version (so the digest is interpretable later). */
|
|
12
|
+
algorithm: string;
|
|
13
|
+
/**
|
|
14
|
+
* Hex SHA-256 digest over the canonical normalized trace content. One-way digest
|
|
15
|
+
* ONLY — never raw content. Same session → same value; different session → different.
|
|
16
|
+
*/
|
|
17
|
+
content_sha256: string;
|
|
18
|
+
/** Non-sensitive structural count: number of messages hashed. */
|
|
19
|
+
message_count: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Compute the per-run distinctness fingerprint for a captured trace.
|
|
23
|
+
*
|
|
24
|
+
* Returns a digest-only object. The raw `canonicalContent` is consumed by the hash
|
|
25
|
+
* and discarded; it is never returned or stored. This is the smallest safe
|
|
26
|
+
* distinctness signal: it distinguishes a genuinely different session from a
|
|
27
|
+
* re-capture of the same session without exposing any session content.
|
|
28
|
+
*/
|
|
29
|
+
export declare function computeTraceFingerprint(trace: AgentTrace): TraceFingerprint;
|
|
30
|
+
/**
|
|
31
|
+
* Minimal per-run record the distinctness classifier needs. Carries ONLY a
|
|
32
|
+
* non-sensitive fingerprint digest (optional) — no content, no aggregate metrics
|
|
33
|
+
* masquerading as proof. A record whose fingerprint is absent/unverifiable is
|
|
34
|
+
* counted as `not_verified`, NEVER as distinct.
|
|
35
|
+
*/
|
|
36
|
+
export interface DistinctnessRecord {
|
|
37
|
+
/** Stable per-run identifier for reporting (e.g. session id or run dir). Non-sensitive. */
|
|
38
|
+
runId: string;
|
|
39
|
+
/**
|
|
40
|
+
* The verifiable distinctness digest, when available. When undefined/empty, the
|
|
41
|
+
* run's distinctness is NOT verified and it does not contribute to the distinct
|
|
42
|
+
* count.
|
|
43
|
+
*/
|
|
44
|
+
content_sha256?: string | null;
|
|
45
|
+
}
|
|
46
|
+
export interface DistinctnessResult {
|
|
47
|
+
/**
|
|
48
|
+
* Number of DISTINCT verified sessions: the count of unique non-empty
|
|
49
|
+
* `content_sha256` values. Re-captures (same digest) collapse to one.
|
|
50
|
+
*/
|
|
51
|
+
distinct_verified_count: number;
|
|
52
|
+
/** The unique verified fingerprints (sorted), for citation. */
|
|
53
|
+
distinct_fingerprints: string[];
|
|
54
|
+
/**
|
|
55
|
+
* Run ids whose distinctness could NOT be verified (missing/empty fingerprint).
|
|
56
|
+
* These are reported as `not_verified` and are NOT added to the distinct count.
|
|
57
|
+
*/
|
|
58
|
+
not_verified_run_ids: string[];
|
|
59
|
+
/**
|
|
60
|
+
* Total runs considered (verified-distinct contributions + duplicates +
|
|
61
|
+
* not_verified). Provided so a report can never silently drop runs.
|
|
62
|
+
*/
|
|
63
|
+
total_runs: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Classify a set of per-run records into a de-duplicated distinct count plus an
|
|
67
|
+
* explicit `not_verified` bucket.
|
|
68
|
+
*
|
|
69
|
+
* Rules (the anti-overcount contract):
|
|
70
|
+
* - same fingerprint → counted once (de-dup).
|
|
71
|
+
* - different fingerprint → counted as distinct.
|
|
72
|
+
* - missing/empty fingerprint → `not_verified`; does NOT inflate the distinct count.
|
|
73
|
+
*
|
|
74
|
+
* Aggregate metrics are intentionally NOT an input here: matching aggregates alone
|
|
75
|
+
* never makes two runs "the same", and unverifiable distinctness is never upgraded
|
|
76
|
+
* to distinct. The fingerprint is the only signal that moves a run into the
|
|
77
|
+
* verified-distinct set.
|
|
78
|
+
*/
|
|
79
|
+
export declare function classifyDistinctness(records: readonly DistinctnessRecord[]): DistinctnessResult;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { contentHash } from "./content-hash.js";
|
|
2
|
+
/**
|
|
3
|
+
* Per-run trace distinctness fingerprint.
|
|
4
|
+
*
|
|
5
|
+
* PURPOSE (evidence integrity): give each captured run a verifiable, non-sensitive
|
|
6
|
+
* distinctness signal so that genuinely-different sessions are distinguishable from
|
|
7
|
+
* re-captures of the SAME session. This prevents over-counting `real_captured` N
|
|
8
|
+
* (the prior failure mode: re-running capture over the same 3 static sessions and
|
|
9
|
+
* reporting them as new because distinctness was asserted by size/date, not verified).
|
|
10
|
+
*
|
|
11
|
+
* PRIVACY (load-bearing): the emitted value is a one-way SHA-256 DIGEST ONLY. Raw
|
|
12
|
+
* message content, prompts, completions, tool output, file contents, and secrets are
|
|
13
|
+
* fed INTO the hash (one-way) and are NEVER emitted. `computeTraceFingerprint`
|
|
14
|
+
* returns only the hex digest + non-sensitive structural counts; it returns no
|
|
15
|
+
* message text. Asserting non-content is also covered by a dedicated test
|
|
16
|
+
* (`tests/core/trace-fingerprint.test.ts`).
|
|
17
|
+
*
|
|
18
|
+
* WHAT IS HASHED (the canonical normalized trace content): the ordered message
|
|
19
|
+
* stream as `role | toolName | content`, joined with control-character separators,
|
|
20
|
+
* prefixed with the model. Capture-time-varying fields (capturedAt / generatedAt
|
|
21
|
+
* timestamps, absolute source path, the fingerprint field itself, durationMs) are
|
|
22
|
+
* deliberately EXCLUDED so the same session captured twice yields the SAME
|
|
23
|
+
* fingerprint, while a genuinely different session yields a different one.
|
|
24
|
+
*
|
|
25
|
+
* HONESTY: this is a distinctness signal, NOT a "byte-identical sessions" claim and
|
|
26
|
+
* NOT a semantic/billing/commitment claim. If only aggregate metrics match but no
|
|
27
|
+
* fingerprint is available, distinctness is reported as `not_verified` — never
|
|
28
|
+
* inflated into a distinct count. See `classifyDistinctness`.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Field/record separators inside the canonical content string. ASCII control
|
|
32
|
+
* characters (Unit Separator U+001F / Record Separator U+001E) are used so message
|
|
33
|
+
* text cannot accidentally forge a record boundary (collision-resistance of the
|
|
34
|
+
* canonicalization). Built via String.fromCharCode so no raw control chars sit in source.
|
|
35
|
+
*/
|
|
36
|
+
const FIELD_SEP = String.fromCharCode(0x1f);
|
|
37
|
+
const RECORD_SEP = String.fromCharCode(0x1e);
|
|
38
|
+
/**
|
|
39
|
+
* Build the canonical content string that the fingerprint digests.
|
|
40
|
+
*
|
|
41
|
+
* INTERNAL ONLY — this string contains raw message content and MUST NOT be emitted
|
|
42
|
+
* anywhere. It exists solely as input to the one-way hash. Callers receive only the
|
|
43
|
+
* resulting digest from `computeTraceFingerprint`.
|
|
44
|
+
*/
|
|
45
|
+
function canonicalContent(trace) {
|
|
46
|
+
const head = `model${FIELD_SEP}${trace.model}`;
|
|
47
|
+
const body = trace.messages
|
|
48
|
+
.map((m) => [m.role, m.toolName ?? "", m.content].join(FIELD_SEP))
|
|
49
|
+
.join(RECORD_SEP);
|
|
50
|
+
return head + RECORD_SEP + body;
|
|
51
|
+
}
|
|
52
|
+
/** Algorithm identifier surfaced alongside the digest so the signal is self-describing. */
|
|
53
|
+
export const TRACE_FINGERPRINT_ALGORITHM = "sha256-canonical-content-v1";
|
|
54
|
+
/**
|
|
55
|
+
* Compute the per-run distinctness fingerprint for a captured trace.
|
|
56
|
+
*
|
|
57
|
+
* Returns a digest-only object. The raw `canonicalContent` is consumed by the hash
|
|
58
|
+
* and discarded; it is never returned or stored. This is the smallest safe
|
|
59
|
+
* distinctness signal: it distinguishes a genuinely different session from a
|
|
60
|
+
* re-capture of the same session without exposing any session content.
|
|
61
|
+
*/
|
|
62
|
+
export function computeTraceFingerprint(trace) {
|
|
63
|
+
return {
|
|
64
|
+
algorithm: TRACE_FINGERPRINT_ALGORITHM,
|
|
65
|
+
content_sha256: contentHash(canonicalContent(trace)),
|
|
66
|
+
message_count: trace.messages.length
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Classify a set of per-run records into a de-duplicated distinct count plus an
|
|
71
|
+
* explicit `not_verified` bucket.
|
|
72
|
+
*
|
|
73
|
+
* Rules (the anti-overcount contract):
|
|
74
|
+
* - same fingerprint → counted once (de-dup).
|
|
75
|
+
* - different fingerprint → counted as distinct.
|
|
76
|
+
* - missing/empty fingerprint → `not_verified`; does NOT inflate the distinct count.
|
|
77
|
+
*
|
|
78
|
+
* Aggregate metrics are intentionally NOT an input here: matching aggregates alone
|
|
79
|
+
* never makes two runs "the same", and unverifiable distinctness is never upgraded
|
|
80
|
+
* to distinct. The fingerprint is the only signal that moves a run into the
|
|
81
|
+
* verified-distinct set.
|
|
82
|
+
*/
|
|
83
|
+
export function classifyDistinctness(records) {
|
|
84
|
+
const verified = new Set();
|
|
85
|
+
const notVerified = [];
|
|
86
|
+
for (const r of records) {
|
|
87
|
+
const fp = r.content_sha256;
|
|
88
|
+
if (typeof fp === "string" && fp.length > 0) {
|
|
89
|
+
verified.add(fp);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
notVerified.push(r.runId);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
distinct_verified_count: verified.size,
|
|
97
|
+
distinct_fingerprints: [...verified].sort(),
|
|
98
|
+
not_verified_run_ids: notVerified,
|
|
99
|
+
total_runs: records.length
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=trace-fingerprint.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type TraceAdapterSource, type TraceAdapterStatus } from "./trace-adapters.js";
|
|
2
|
+
import type { AgentTrace } from "./types.js";
|
|
3
|
+
export type TraceIntakeSource = TraceAdapterSource;
|
|
4
|
+
export type TraceIntakeStatus = TraceAdapterStatus;
|
|
5
|
+
/**
|
|
6
|
+
* Filename for the normalized AgentTrace written by `import`. This deliberately matches the
|
|
7
|
+
* `captured-trace.json` produced by every `capture` command so the documented follow-up chain
|
|
8
|
+
* (`compaction analyze ./my-trace/captured-trace.json`, etc., printed by `compaction init`)
|
|
9
|
+
* resolves identically whether the trace came from capture or import. Keeping the import output
|
|
10
|
+
* name distinct from the capture output name previously broke the copy-pasteable init chain.
|
|
11
|
+
*/
|
|
12
|
+
export declare const IMPORTED_TRACE_FILENAME = "captured-trace.json";
|
|
13
|
+
export interface TraceIntakeReport {
|
|
14
|
+
input_path: string;
|
|
15
|
+
source: TraceIntakeSource;
|
|
16
|
+
adapter_id: TraceIntakeSource;
|
|
17
|
+
status: TraceIntakeStatus;
|
|
18
|
+
generated_at: string;
|
|
19
|
+
output_trace_id: string | null;
|
|
20
|
+
message_count: number;
|
|
21
|
+
supported_format_detected: boolean;
|
|
22
|
+
warnings: string[];
|
|
23
|
+
failures: string[];
|
|
24
|
+
normalization_steps: string[];
|
|
25
|
+
skipped_fields: string[];
|
|
26
|
+
source_metadata: Record<string, unknown>;
|
|
27
|
+
recommended_next_command: string | null;
|
|
28
|
+
}
|
|
29
|
+
export interface TraceIntakeArtifacts {
|
|
30
|
+
report: TraceIntakeReport;
|
|
31
|
+
normalizedTrace: AgentTrace | null;
|
|
32
|
+
paths: {
|
|
33
|
+
normalizedTracePath: string;
|
|
34
|
+
intakeReportJsonPath: string;
|
|
35
|
+
intakeReportMarkdownPath: string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export interface ImportTraceOptions {
|
|
39
|
+
operatorExport?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export declare function importTraceFile(inputPath: string, source: string, outputDirectory: string, options?: ImportTraceOptions): Promise<TraceIntakeArtifacts>;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { assertTraceAdapterSource, getTraceAdapter, parseTraceAdapterRawContent } from "./trace-adapters.js";
|
|
4
|
+
/**
|
|
5
|
+
* Filename for the normalized AgentTrace written by `import`. This deliberately matches the
|
|
6
|
+
* `captured-trace.json` produced by every `capture` command so the documented follow-up chain
|
|
7
|
+
* (`compaction analyze ./my-trace/captured-trace.json`, etc., printed by `compaction init`)
|
|
8
|
+
* resolves identically whether the trace came from capture or import. Keeping the import output
|
|
9
|
+
* name distinct from the capture output name previously broke the copy-pasteable init chain.
|
|
10
|
+
*/
|
|
11
|
+
export const IMPORTED_TRACE_FILENAME = "captured-trace.json";
|
|
12
|
+
function markdownList(values, emptyText) {
|
|
13
|
+
if (values.length === 0) {
|
|
14
|
+
return `- ${emptyText}`;
|
|
15
|
+
}
|
|
16
|
+
return values.map((value) => `- ${value}`).join("\n");
|
|
17
|
+
}
|
|
18
|
+
function formatMetadata(metadata) {
|
|
19
|
+
const entries = Object.entries(metadata);
|
|
20
|
+
if (entries.length === 0) {
|
|
21
|
+
return "- No source metadata.";
|
|
22
|
+
}
|
|
23
|
+
return entries.map(([key, value]) => `- ${key}: ${String(value)}`).join("\n");
|
|
24
|
+
}
|
|
25
|
+
function formatIntakeReportMarkdown(report) {
|
|
26
|
+
return [
|
|
27
|
+
"# Trace Intake Report",
|
|
28
|
+
"",
|
|
29
|
+
"## Summary",
|
|
30
|
+
"",
|
|
31
|
+
`- Status: ${report.status}`,
|
|
32
|
+
`- Supported format detected: ${report.supported_format_detected ? "yes" : "no"}`,
|
|
33
|
+
`- Output trace ID: ${report.output_trace_id ?? "none"}`,
|
|
34
|
+
`- Message count: ${report.message_count}`,
|
|
35
|
+
`- Generated at: ${report.generated_at}`,
|
|
36
|
+
"",
|
|
37
|
+
"## Source",
|
|
38
|
+
"",
|
|
39
|
+
`- Input path: ${report.input_path}`,
|
|
40
|
+
`- Requested source: ${report.source}`,
|
|
41
|
+
`- Adapter: ${report.adapter_id}`,
|
|
42
|
+
"",
|
|
43
|
+
"## Source Metadata",
|
|
44
|
+
"",
|
|
45
|
+
formatMetadata(report.source_metadata),
|
|
46
|
+
"",
|
|
47
|
+
"## Normalization",
|
|
48
|
+
"",
|
|
49
|
+
markdownList(report.normalization_steps, "No normalization steps were applied."),
|
|
50
|
+
"",
|
|
51
|
+
"## Warnings",
|
|
52
|
+
"",
|
|
53
|
+
markdownList(report.warnings, "No warnings."),
|
|
54
|
+
"",
|
|
55
|
+
"## Failures",
|
|
56
|
+
"",
|
|
57
|
+
markdownList(report.failures, "No failures."),
|
|
58
|
+
"",
|
|
59
|
+
"## Recommended Next Command",
|
|
60
|
+
"",
|
|
61
|
+
report.recommended_next_command ? `\`${report.recommended_next_command}\`` : "No next command is recommended until intake succeeds.",
|
|
62
|
+
"",
|
|
63
|
+
"## Limitations",
|
|
64
|
+
"",
|
|
65
|
+
"- External Trace Intake v0 is local and file-based only.",
|
|
66
|
+
"- Trace adapters are local file normalizers, not live runtime/provider integrations.",
|
|
67
|
+
"- It does not upload data or call model/provider APIs.",
|
|
68
|
+
"- Live provider/runtime integrations are future work; source-backed adapters read only local export files.",
|
|
69
|
+
"- Codex exec JSONL support is limited to local files and does not launch Codex or call provider APIs.",
|
|
70
|
+
"- Unsupported fields are preserved only when they fit the internal AgentTrace message metadata shape.",
|
|
71
|
+
""
|
|
72
|
+
].join("\n");
|
|
73
|
+
}
|
|
74
|
+
function buildReport(params) {
|
|
75
|
+
return {
|
|
76
|
+
input_path: params.inputPath,
|
|
77
|
+
source: params.source,
|
|
78
|
+
adapter_id: params.adapterId,
|
|
79
|
+
status: params.status,
|
|
80
|
+
generated_at: params.generatedAt,
|
|
81
|
+
output_trace_id: params.outputTraceId,
|
|
82
|
+
message_count: params.messageCount,
|
|
83
|
+
supported_format_detected: params.supportedFormatDetected,
|
|
84
|
+
warnings: params.warnings,
|
|
85
|
+
failures: params.failures,
|
|
86
|
+
normalization_steps: params.normalizationSteps,
|
|
87
|
+
skipped_fields: params.skippedFields,
|
|
88
|
+
source_metadata: params.sourceMetadata,
|
|
89
|
+
recommended_next_command: params.status === "fail" ? null : `compaction analyze ${params.normalizedTracePath}`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async function writeIntakeArtifacts(outputDirectory, report, normalizedTrace) {
|
|
93
|
+
await mkdir(outputDirectory, { recursive: true });
|
|
94
|
+
const normalizedTracePath = path.join(outputDirectory, IMPORTED_TRACE_FILENAME);
|
|
95
|
+
const intakeReportJsonPath = path.join(outputDirectory, "intake-report.json");
|
|
96
|
+
const intakeReportMarkdownPath = path.join(outputDirectory, "intake-report.md");
|
|
97
|
+
if (normalizedTrace) {
|
|
98
|
+
await writeFile(normalizedTracePath, `${JSON.stringify(normalizedTrace, null, 2)}\n`, "utf8");
|
|
99
|
+
}
|
|
100
|
+
await writeFile(intakeReportJsonPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
|
101
|
+
await writeFile(intakeReportMarkdownPath, formatIntakeReportMarkdown(report), "utf8");
|
|
102
|
+
return {
|
|
103
|
+
report,
|
|
104
|
+
normalizedTrace,
|
|
105
|
+
paths: {
|
|
106
|
+
normalizedTracePath,
|
|
107
|
+
intakeReportJsonPath,
|
|
108
|
+
intakeReportMarkdownPath
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export async function importTraceFile(inputPath, source, outputDirectory, options = {}) {
|
|
113
|
+
assertTraceAdapterSource(source);
|
|
114
|
+
const rawContent = await readFile(inputPath, "utf8");
|
|
115
|
+
const generatedAt = new Date().toISOString();
|
|
116
|
+
const normalizedTracePath = path.join(outputDirectory, IMPORTED_TRACE_FILENAME);
|
|
117
|
+
const adapter = getTraceAdapter(source);
|
|
118
|
+
const parsedInput = parseTraceAdapterRawContent(rawContent, source);
|
|
119
|
+
if (parsedInput.failures.length > 0 || parsedInput.input === null) {
|
|
120
|
+
const report = buildReport({
|
|
121
|
+
inputPath,
|
|
122
|
+
source,
|
|
123
|
+
adapterId: adapter.id,
|
|
124
|
+
status: "fail",
|
|
125
|
+
generatedAt,
|
|
126
|
+
outputTraceId: null,
|
|
127
|
+
messageCount: 0,
|
|
128
|
+
supportedFormatDetected: false,
|
|
129
|
+
warnings: [],
|
|
130
|
+
failures: parsedInput.failures,
|
|
131
|
+
normalizationSteps: parsedInput.normalization_steps,
|
|
132
|
+
skippedFields: [],
|
|
133
|
+
sourceMetadata: {
|
|
134
|
+
adapter_id: adapter.id,
|
|
135
|
+
supported_source: adapter.supportedSource,
|
|
136
|
+
local_file_normalizer: true,
|
|
137
|
+
live_provider_integration: false,
|
|
138
|
+
...parsedInput.source_metadata
|
|
139
|
+
},
|
|
140
|
+
normalizedTracePath
|
|
141
|
+
});
|
|
142
|
+
return writeIntakeArtifacts(outputDirectory, report, null);
|
|
143
|
+
}
|
|
144
|
+
const result = adapter.normalize(parsedInput.input, { rawContent, operatorExport: options.operatorExport === true });
|
|
145
|
+
const normalizedTrace = result.trace;
|
|
146
|
+
const report = buildReport({
|
|
147
|
+
inputPath,
|
|
148
|
+
source,
|
|
149
|
+
adapterId: adapter.id,
|
|
150
|
+
status: result.status,
|
|
151
|
+
generatedAt,
|
|
152
|
+
outputTraceId: normalizedTrace?.id ?? null,
|
|
153
|
+
messageCount: normalizedTrace?.messages.length ?? 0,
|
|
154
|
+
supportedFormatDetected: normalizedTrace !== null,
|
|
155
|
+
warnings: result.warnings,
|
|
156
|
+
failures: result.failures,
|
|
157
|
+
normalizationSteps: [...parsedInput.normalization_steps, ...result.normalization_steps],
|
|
158
|
+
skippedFields: result.skipped_fields,
|
|
159
|
+
sourceMetadata: { ...parsedInput.source_metadata, ...result.source_metadata },
|
|
160
|
+
normalizedTracePath
|
|
161
|
+
});
|
|
162
|
+
return writeIntakeArtifacts(outputDirectory, report, result.status === "fail" ? null : normalizedTrace);
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=trace-intake.js.map
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { AgentTrace } from "./types.js";
|
|
3
|
+
export declare const CURRENT_AGENT_TRACE_ARTIFACT_VERSION = "agent-trace-v1";
|
|
4
|
+
export declare const agentTraceSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
5
|
+
id: z.ZodString;
|
|
6
|
+
title: z.ZodString;
|
|
7
|
+
artifactVersion: z.ZodOptional<z.ZodString>;
|
|
8
|
+
artifact_version: z.ZodOptional<z.ZodString>;
|
|
9
|
+
source: z.ZodOptional<z.ZodEnum<["manual", "cli_wrapper", "local_command", "demo", "real_captured", "provider_usage", "codex_import"]>>;
|
|
10
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
11
|
+
created_at: z.ZodOptional<z.ZodString>;
|
|
12
|
+
generatedAt: z.ZodOptional<z.ZodString>;
|
|
13
|
+
generated_at: z.ZodOptional<z.ZodString>;
|
|
14
|
+
model: z.ZodString;
|
|
15
|
+
command: z.ZodOptional<z.ZodObject<{
|
|
16
|
+
command: z.ZodString;
|
|
17
|
+
args: z.ZodArray<z.ZodString, "many">;
|
|
18
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
19
|
+
shell: z.ZodOptional<z.ZodString>;
|
|
20
|
+
}, "strip", z.ZodTypeAny, {
|
|
21
|
+
command: string;
|
|
22
|
+
args: string[];
|
|
23
|
+
cwd?: string | undefined;
|
|
24
|
+
shell?: string | undefined;
|
|
25
|
+
}, {
|
|
26
|
+
command: string;
|
|
27
|
+
args: string[];
|
|
28
|
+
cwd?: string | undefined;
|
|
29
|
+
shell?: string | undefined;
|
|
30
|
+
}>>;
|
|
31
|
+
durationMs: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
duration_ms: z.ZodOptional<z.ZodNumber>;
|
|
33
|
+
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
exit_code: z.ZodOptional<z.ZodNumber>;
|
|
35
|
+
messages: z.ZodArray<z.ZodObject<{
|
|
36
|
+
id: z.ZodString;
|
|
37
|
+
role: z.ZodEnum<["system", "user", "assistant", "tool", "stdout", "stderr"]>;
|
|
38
|
+
content: z.ZodString;
|
|
39
|
+
timestamp: z.ZodString;
|
|
40
|
+
toolName: z.ZodOptional<z.ZodString>;
|
|
41
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
42
|
+
}, "strip", z.ZodTypeAny, {
|
|
43
|
+
id: string;
|
|
44
|
+
role: "system" | "user" | "assistant" | "tool" | "stdout" | "stderr";
|
|
45
|
+
content: string;
|
|
46
|
+
timestamp: string;
|
|
47
|
+
toolName?: string | undefined;
|
|
48
|
+
metadata?: Record<string, unknown> | undefined;
|
|
49
|
+
}, {
|
|
50
|
+
id: string;
|
|
51
|
+
role: "system" | "user" | "assistant" | "tool" | "stdout" | "stderr";
|
|
52
|
+
content: string;
|
|
53
|
+
timestamp: string;
|
|
54
|
+
toolName?: string | undefined;
|
|
55
|
+
metadata?: Record<string, unknown> | undefined;
|
|
56
|
+
}>, "many">;
|
|
57
|
+
}, "strip", z.ZodTypeAny, {
|
|
58
|
+
model: string;
|
|
59
|
+
id: string;
|
|
60
|
+
title: string;
|
|
61
|
+
messages: {
|
|
62
|
+
id: string;
|
|
63
|
+
role: "system" | "user" | "assistant" | "tool" | "stdout" | "stderr";
|
|
64
|
+
content: string;
|
|
65
|
+
timestamp: string;
|
|
66
|
+
toolName?: string | undefined;
|
|
67
|
+
metadata?: Record<string, unknown> | undefined;
|
|
68
|
+
}[];
|
|
69
|
+
command?: {
|
|
70
|
+
command: string;
|
|
71
|
+
args: string[];
|
|
72
|
+
cwd?: string | undefined;
|
|
73
|
+
shell?: string | undefined;
|
|
74
|
+
} | undefined;
|
|
75
|
+
artifactVersion?: string | undefined;
|
|
76
|
+
artifact_version?: string | undefined;
|
|
77
|
+
source?: "manual" | "cli_wrapper" | "local_command" | "demo" | "real_captured" | "provider_usage" | "codex_import" | undefined;
|
|
78
|
+
createdAt?: string | undefined;
|
|
79
|
+
created_at?: string | undefined;
|
|
80
|
+
generatedAt?: string | undefined;
|
|
81
|
+
generated_at?: string | undefined;
|
|
82
|
+
durationMs?: number | undefined;
|
|
83
|
+
duration_ms?: number | undefined;
|
|
84
|
+
exitCode?: number | undefined;
|
|
85
|
+
exit_code?: number | undefined;
|
|
86
|
+
}, {
|
|
87
|
+
model: string;
|
|
88
|
+
id: string;
|
|
89
|
+
title: string;
|
|
90
|
+
messages: {
|
|
91
|
+
id: string;
|
|
92
|
+
role: "system" | "user" | "assistant" | "tool" | "stdout" | "stderr";
|
|
93
|
+
content: string;
|
|
94
|
+
timestamp: string;
|
|
95
|
+
toolName?: string | undefined;
|
|
96
|
+
metadata?: Record<string, unknown> | undefined;
|
|
97
|
+
}[];
|
|
98
|
+
command?: {
|
|
99
|
+
command: string;
|
|
100
|
+
args: string[];
|
|
101
|
+
cwd?: string | undefined;
|
|
102
|
+
shell?: string | undefined;
|
|
103
|
+
} | undefined;
|
|
104
|
+
artifactVersion?: string | undefined;
|
|
105
|
+
artifact_version?: string | undefined;
|
|
106
|
+
source?: "manual" | "cli_wrapper" | "local_command" | "demo" | "real_captured" | "provider_usage" | "codex_import" | undefined;
|
|
107
|
+
createdAt?: string | undefined;
|
|
108
|
+
created_at?: string | undefined;
|
|
109
|
+
generatedAt?: string | undefined;
|
|
110
|
+
generated_at?: string | undefined;
|
|
111
|
+
durationMs?: number | undefined;
|
|
112
|
+
duration_ms?: number | undefined;
|
|
113
|
+
exitCode?: number | undefined;
|
|
114
|
+
exit_code?: number | undefined;
|
|
115
|
+
}>, {
|
|
116
|
+
model: string;
|
|
117
|
+
id: string;
|
|
118
|
+
title: string;
|
|
119
|
+
messages: {
|
|
120
|
+
id: string;
|
|
121
|
+
role: "system" | "user" | "assistant" | "tool" | "stdout" | "stderr";
|
|
122
|
+
content: string;
|
|
123
|
+
timestamp: string;
|
|
124
|
+
toolName?: string | undefined;
|
|
125
|
+
metadata?: Record<string, unknown> | undefined;
|
|
126
|
+
}[];
|
|
127
|
+
command?: {
|
|
128
|
+
command: string;
|
|
129
|
+
args: string[];
|
|
130
|
+
cwd?: string | undefined;
|
|
131
|
+
shell?: string | undefined;
|
|
132
|
+
} | undefined;
|
|
133
|
+
artifactVersion?: string | undefined;
|
|
134
|
+
artifact_version?: string | undefined;
|
|
135
|
+
source?: "manual" | "cli_wrapper" | "local_command" | "demo" | "real_captured" | "provider_usage" | "codex_import" | undefined;
|
|
136
|
+
createdAt?: string | undefined;
|
|
137
|
+
created_at?: string | undefined;
|
|
138
|
+
generatedAt?: string | undefined;
|
|
139
|
+
generated_at?: string | undefined;
|
|
140
|
+
durationMs?: number | undefined;
|
|
141
|
+
duration_ms?: number | undefined;
|
|
142
|
+
exitCode?: number | undefined;
|
|
143
|
+
exit_code?: number | undefined;
|
|
144
|
+
}, {
|
|
145
|
+
model: string;
|
|
146
|
+
id: string;
|
|
147
|
+
title: string;
|
|
148
|
+
messages: {
|
|
149
|
+
id: string;
|
|
150
|
+
role: "system" | "user" | "assistant" | "tool" | "stdout" | "stderr";
|
|
151
|
+
content: string;
|
|
152
|
+
timestamp: string;
|
|
153
|
+
toolName?: string | undefined;
|
|
154
|
+
metadata?: Record<string, unknown> | undefined;
|
|
155
|
+
}[];
|
|
156
|
+
command?: {
|
|
157
|
+
command: string;
|
|
158
|
+
args: string[];
|
|
159
|
+
cwd?: string | undefined;
|
|
160
|
+
shell?: string | undefined;
|
|
161
|
+
} | undefined;
|
|
162
|
+
artifactVersion?: string | undefined;
|
|
163
|
+
artifact_version?: string | undefined;
|
|
164
|
+
source?: "manual" | "cli_wrapper" | "local_command" | "demo" | "real_captured" | "provider_usage" | "codex_import" | undefined;
|
|
165
|
+
createdAt?: string | undefined;
|
|
166
|
+
created_at?: string | undefined;
|
|
167
|
+
generatedAt?: string | undefined;
|
|
168
|
+
generated_at?: string | undefined;
|
|
169
|
+
durationMs?: number | undefined;
|
|
170
|
+
duration_ms?: number | undefined;
|
|
171
|
+
exitCode?: number | undefined;
|
|
172
|
+
exit_code?: number | undefined;
|
|
173
|
+
}>, AgentTrace, {
|
|
174
|
+
model: string;
|
|
175
|
+
id: string;
|
|
176
|
+
title: string;
|
|
177
|
+
messages: {
|
|
178
|
+
id: string;
|
|
179
|
+
role: "system" | "user" | "assistant" | "tool" | "stdout" | "stderr";
|
|
180
|
+
content: string;
|
|
181
|
+
timestamp: string;
|
|
182
|
+
toolName?: string | undefined;
|
|
183
|
+
metadata?: Record<string, unknown> | undefined;
|
|
184
|
+
}[];
|
|
185
|
+
command?: {
|
|
186
|
+
command: string;
|
|
187
|
+
args: string[];
|
|
188
|
+
cwd?: string | undefined;
|
|
189
|
+
shell?: string | undefined;
|
|
190
|
+
} | undefined;
|
|
191
|
+
artifactVersion?: string | undefined;
|
|
192
|
+
artifact_version?: string | undefined;
|
|
193
|
+
source?: "manual" | "cli_wrapper" | "local_command" | "demo" | "real_captured" | "provider_usage" | "codex_import" | undefined;
|
|
194
|
+
createdAt?: string | undefined;
|
|
195
|
+
created_at?: string | undefined;
|
|
196
|
+
generatedAt?: string | undefined;
|
|
197
|
+
generated_at?: string | undefined;
|
|
198
|
+
durationMs?: number | undefined;
|
|
199
|
+
duration_ms?: number | undefined;
|
|
200
|
+
exitCode?: number | undefined;
|
|
201
|
+
exit_code?: number | undefined;
|
|
202
|
+
}>;
|
|
203
|
+
export declare function parseTraceFile(traceFile: string): Promise<AgentTrace>;
|