@tangle-network/traces 0.7.0 → 0.8.5

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/index.d.ts CHANGED
@@ -11,13 +11,12 @@ export { HostedClient, createHostedClient, hostedClientFromEnv } from '@tangle-n
11
11
  /**
12
12
  * OTLP-flat-line emitter — the canonical normalized trace shape.
13
13
  *
14
- * Every harness adapter projects its native session log onto `OtlpSpan[]`
15
- * and we serialize one span per JSONL line. This is the exact wire shape
16
- * `@tangle-network/agent-eval`'s `OtlpFileTraceStore` indexes
17
- * (`projectOtlpFlatLine` + `extractOtlpAttributes`). It is a flat subset, NOT
18
- * canonical OpenInference (kind lives in attributes; no resource/scope; root
19
- * parent is null) — external OpenInference engines like HALO need the canonical
20
- * form, which `external.ts` `toCanonicalOpenInference` produces.
14
+ * Every harness adapter projects its native session log onto `OtlpSpan[]`.
15
+ * `serializeSpans` emits one COMPLETE OpenInference span per JSONL line
16
+ * (top-level `kind`, `resource`, `scope`, string `parent_span_id`, plus the
17
+ * `openinference.span.kind` attribute). One standard artifact feeds three
18
+ * consumers unchanged: `@tangle-network/agent-eval`'s `OtlpFileTraceStore`
19
+ * (which reads the attribute vocabulary), HALO, and any OpenInference tool.
21
20
  *
22
21
  * Attribute vocabulary the downstream analysts key off:
23
22
  * - `openinference.span.kind` → span kind (AGENT | LLM | TOOL | CHAIN)
@@ -73,7 +72,15 @@ interface SpanInput {
73
72
  * so the behavioral analyst's "no LLM data" case stays honest.
74
73
  */
75
74
  declare function span(input: SpanInput): OtlpSpan;
76
- /** Serialize spans to OTLP-JSONL (one span per line, trailing newline). */
75
+ /** Project an in-memory span to a COMPLETE OpenInference span: the standard shape
76
+ * OTel/OpenInference consumers (and HALO) expect — top-level `kind`, `resource`,
77
+ * `scope`, and a string `parent_span_id` ("" at the root) — while keeping the
78
+ * attribute vocabulary (incl. `openinference.span.kind`) our own analysts read.
79
+ * One artifact feeds our pipeline, HALO, and any OpenInference tool. */
80
+ declare function toOpenInferenceSpan(s: OtlpSpan): Record<string, unknown>;
81
+ /** Serialize spans to OpenInference JSONL (one complete span per line). This is a
82
+ * standard OpenInference representation: it feeds our analysts, HALO, and other
83
+ * OpenInference tools directly — no per-tool conversion. */
77
84
  declare function serializeSpans(spans: readonly OtlpSpan[]): string;
78
85
  /** Write spans to an OTLP-JSONL file (a temp file when no path is given). */
79
86
  declare function writeOtlpFile(spans: readonly OtlpSpan[], outPath?: string): Promise<string>;
@@ -141,6 +148,16 @@ declare const ATTR: {
141
148
  readonly INGEST_SOURCE: "tangle.ingest_source";
142
149
  readonly HARNESS: "tangle.harness";
143
150
  readonly CWD: "tangle.cwd";
151
+ /** THE per-session grouping key the spine derives subjects from
152
+ * (`deriveSubjectKey` reads `tangle.subject.key` first). Resolves to the git
153
+ * remote (host/owner/repo) when readable, else the cwd path basename. */
154
+ readonly SUBJECT_KEY: "tangle.subject.key";
155
+ /** Normalized git remote (e.g. `github.com/tangle-network/agent-dev-container`). */
156
+ readonly GIT_REPOSITORY: "git.repository";
157
+ /** Current branch at conversion time. */
158
+ readonly GIT_BRANCH_NAME: "git.branch";
159
+ /** HEAD short sha at conversion time. */
160
+ readonly GIT_COMMIT: "git.commit";
144
161
  readonly GIT_BRANCH: "tangle.git_branch";
145
162
  readonly HOST: "tangle.host";
146
163
  /** Basename of the session file. (Renamed from the ambiguous `tangle.source`,
@@ -193,6 +210,13 @@ interface AdapterSelection {
193
210
  * A named harness that doesn't resolve throws rather than silently dropping. */
194
211
  declare function selectAdapters(opts: AdapterSelection): HarnessTraceAdapter[];
195
212
 
213
+ /**
214
+ * Parse one session to spans and stamp per-session repo/git resource attrs
215
+ * (`tangle.subject.key` etc.) derived from the ref's cwd. Every OTLP-producing
216
+ * path funnels through here so the spine can group by repo. Repo resolution is
217
+ * computed ONCE per session; it is fail-safe and never throws.
218
+ */
219
+ declare function parseSession(adapter: HarnessTraceAdapter, ref: SessionRef): Promise<OtlpSpan[]>;
196
220
  interface ScanOptions extends AdapterSelection {
197
221
  /** Filter by working directory (exact/prefix). */
198
222
  cwd?: string;
@@ -215,6 +239,27 @@ interface ScannedSession {
215
239
  * errors route to `onError` and skip that adapter/session, never aborting. */
216
240
  declare function scanSessions(opts: ScanOptions): AsyncGenerator<ScannedSession>;
217
241
 
242
+ /** Resource-attribute keys this resolver may stamp. */
243
+ type RepoAttrs = Partial<Record<typeof ATTR.SUBJECT_KEY | typeof ATTR.GIT_REPOSITORY | typeof ATTR.GIT_BRANCH_NAME | typeof ATTR.GIT_COMMIT | typeof ATTR.CWD, string>>;
244
+ /**
245
+ * Normalize a git remote url to `host/owner/repo`, dropping scheme, auth, the
246
+ * `.git` suffix, and any trailing slash. Handles both `https://` and the
247
+ * `git@host:owner/repo.git` SCP-style forms. Returns null when unparseable.
248
+ */
249
+ declare function normalizeRemote(url: string): string | null;
250
+ /**
251
+ * Resolve per-session repo/git resource attributes from a session's cwd.
252
+ * Fail-safe and never throws; see the module doc for the derivation contract.
253
+ */
254
+ declare function resolveRepoAttrs(cwd: string | null | undefined): Promise<RepoAttrs>;
255
+ /**
256
+ * Stamp resolved repo attrs onto every span's attributes (so they land in the
257
+ * OTLP resource attributes via `toOpenInferenceSpan`). Additive — existing
258
+ * `service.name` / `agent.name` are untouched. Mutates in place and returns the
259
+ * same array for ergonomic chaining. A no-op when `attrs` is empty.
260
+ */
261
+ declare function stampRepoAttrs(spans: readonly OtlpSpan[], attrs: RepoAttrs): readonly OtlpSpan[];
262
+
218
263
  /**
219
264
  * Claude Code adapter — `~/.claude/projects/<encoded-cwd>/<session>.jsonl`.
220
265
  *
@@ -453,6 +498,20 @@ declare const CONTENT_CAP = 8000;
453
498
  * visible `… [+N chars]` marker is appended so analysts (and readers) know the
454
499
  * content was truncated rather than silently lost. */
455
500
  declare function capText(raw: string): string;
501
+ /**
502
+ * Who produced a `user.prompt` turn. The trace records every "user" message,
503
+ * but only some are a real human typing — the rest are the harness or another
504
+ * agent feeding the model:
505
+ * - `human` a person typed it
506
+ * - `subagent-spawn` a parent agent spawned a subagent with this prompt
507
+ * - `injected` a synthetic harness prompt (benchmark task, memory, …)
508
+ * - `tool-result` a tool result surfaced as a user turn (rare)
509
+ * Analysts that measure human reactions must filter to `human` only.
510
+ */
511
+ type Actor = 'human' | 'subagent-spawn' | 'injected' | 'tool-result';
512
+ /** Span attribute key for {@link Actor}. New (additive) — not part of the
513
+ * `tangle.sessionId`/`tangle.ingest_source` wire contract. */
514
+ declare const ACTOR_ATTR = "tangle.actor";
456
515
  interface UserPromptInput {
457
516
  traceId: string;
458
517
  spanId: string;
@@ -463,12 +522,70 @@ interface UserPromptInput {
463
522
  service?: string | null;
464
523
  agent?: string | null;
465
524
  step?: number;
525
+ /** Who produced this turn. Defaults to `human` when the adapter can't tell. */
526
+ actor?: Actor;
466
527
  }
467
528
  /** The canonical `user.prompt` span. Every adapter emits the human's turn the
468
529
  * same way — a CHAIN span, because a user message is not an LLM call — so
469
- * analysts see one consistent shape regardless of harness. */
530
+ * analysts see one consistent shape regardless of harness. The `actor`
531
+ * attribute lets analysts separate real human turns from agent-to-agent or
532
+ * injected prompts. */
470
533
  declare function userPromptSpan(o: UserPromptInput): OtlpSpan;
471
534
 
535
+ /**
536
+ * Actor + reaction classification — ported from the proven trace-audit
537
+ * `extract.py` classifier so the CLI and the offline audit agree on what
538
+ * counts as a real human turn and how a human reaction is labelled.
539
+ *
540
+ * Two jobs:
541
+ * 1. {@link claudeActor} / {@link textIsSynthetic} — decide whether a "user"
542
+ * turn is a real human or an injected / agent-spawned prompt. Adapters use
543
+ * the harness's structural signals first (sidechain / userType) and fall
544
+ * back to these text heuristics.
545
+ * 2. {@link classifyReaction} — label a human turn as
546
+ * correction / frustration / praise / jargon / structure complaint, using
547
+ * extract.py's regexes verbatim. The user-reaction analyst keys off this.
548
+ */
549
+
550
+ /** Synthetic harness prompt? (Checks only the head, as extract.py does.) */
551
+ declare function textIsSynthetic(s: string): boolean;
552
+ /** First-turn heuristic: does this read like an agent/subagent spawn prompt
553
+ * (long, or starts with an imperative "you are…/your task…") rather than a
554
+ * person? Ported from extract.py looks_like_agent_prompt. */
555
+ declare function looksLikeAgentPrompt(s: string): boolean;
556
+ /**
557
+ * Derive the actor for a Claude Code user turn from the structural signals the
558
+ * adapter already parses, falling back to the text heuristics above.
559
+ *
560
+ * isSidechain === true → subagent-spawn
561
+ * userType present and !== external → injected
562
+ * synthetic markers in the text → injected
563
+ * first-turn agent-spawn prompt → subagent-spawn
564
+ * otherwise → human
565
+ */
566
+ declare function claudeActor(args: {
567
+ text: string;
568
+ isSidechain?: boolean;
569
+ userType?: string | null;
570
+ isFirstUserTurn?: boolean;
571
+ }): Actor;
572
+ /**
573
+ * Derive the actor for a Codex user message. Codex has no sidechain/userType,
574
+ * so it's text-only: synthetic markers → injected, first-turn agent-spawn
575
+ * brief → injected, otherwise human.
576
+ */
577
+ declare function codexActor(args: {
578
+ text: string;
579
+ isFirstUserTurn?: boolean;
580
+ }): Actor;
581
+ type Reaction = 'correction' | 'frustration' | 'praise' | 'jargon' | 'structure';
582
+ /** Label a human turn with every reaction signal it matches. Mirrors
583
+ * extract.py classify() — lowercased match, multi-label. */
584
+ declare function classifyReaction(text: string): Reaction[];
585
+ /** Reactions that signal the agent did something wrong (the numerator of the
586
+ * corrective-to-positive ratio). `praise` is the positive denominator. */
587
+ declare const CORRECTIVE_REACTIONS: readonly Reaction[];
588
+
472
589
  /**
473
590
  * Run agent-eval's shipped trace pipelines over normalized harness spans.
474
591
  *
@@ -497,6 +614,113 @@ interface PipelineOptions {
497
614
  }
498
615
  declare function runPipelines(spans: readonly OtlpSpan[], opts?: PipelineOptions): Promise<PipelineReport>;
499
616
 
617
+ /**
618
+ * User-reaction analyst — deterministic, $0, no API key.
619
+ *
620
+ * For every real human turn (`actor === 'human'` on a `user.prompt` span) that
621
+ * FOLLOWS an assistant turn, classify the human's reaction (correction /
622
+ * frustration / praise / jargon / structure complaint) with the trace-audit
623
+ * classifier, then roll up:
624
+ * - per-session + corpus signal counts
625
+ * - the corrective-to-positive ratio (how often the human pushed back vs
626
+ * praised)
627
+ * - the top "trigger pairs": the assistant prose that drew the strongest
628
+ * human reaction
629
+ *
630
+ * Findings only consider `actor === 'human'` turns — that's why the actor tag
631
+ * (feature 1) is a hard dependency. An agent-to-agent or injected prompt is not
632
+ * a human reaction and must not pollute the counts.
633
+ */
634
+
635
+ /** Reaction labels in stable render order. */
636
+ declare const REACTIONS: readonly Reaction[];
637
+ interface TriggerPair {
638
+ /** The assistant prose immediately preceding the human reaction. */
639
+ assistant: string;
640
+ /** The human's reacting turn. */
641
+ human: string;
642
+ /** Signals matched on the human turn. */
643
+ reactions: Reaction[];
644
+ sessionId: string;
645
+ }
646
+ interface ReactionSessionReport {
647
+ sessionId: string;
648
+ /** Human turns that followed an assistant turn (the denominator). */
649
+ humanReactionTurns: number;
650
+ signals: Record<Reaction, number>;
651
+ }
652
+ interface ReactionReport {
653
+ sessions: ReactionSessionReport[];
654
+ /** Corpus signal totals. */
655
+ signals: Record<Reaction, number>;
656
+ /** Human turns that followed an assistant turn, corpus-wide. */
657
+ humanReactionTurns: number;
658
+ /** corrective signals / praise signals. Infinity when praise is 0 but
659
+ * corrective > 0; NaN-safe (null) when there are no signals at all. */
660
+ correctiveToPositiveRatio: number | null;
661
+ /** Highest-signal assistant→reaction pairs, most-corrective first. */
662
+ triggerPairs: TriggerPair[];
663
+ }
664
+ /**
665
+ * Build the user-reaction report from normalized spans. Spans may span multiple
666
+ * sessions (corpus run); reactions are scoped per `trace_id`.
667
+ */
668
+ declare function analyzeReactions(spans: readonly OtlpSpan[]): ReactionReport;
669
+
670
+ /**
671
+ * Skill + subagent adoption metrics — deterministic.
672
+ *
673
+ * Reports three things:
674
+ * 1. skill penetration — % of sessions that invoked any skill
675
+ * 2. per-skill invocation frequency
676
+ * 3. subagent (Task/Agent) spawn frequency
677
+ *
678
+ * CRITICAL undercount fix: the trace-level `Skill` tool-use count only sees
679
+ * skills a session invoked *interactively*. Skills dispatched inside an
680
+ * automation loop (e.g. `/evolve`, `/converge`) are logged to
681
+ * `.evolve/skill-runs.jsonl` under the session's cwd and never surface as a
682
+ * `Skill` tool span — historically ~370× more runs than the trace count. So we
683
+ * read those files too and report "explicit invocations" and "loop-dispatched
684
+ * runs" SEPARATELY, so neither silently reads as zero.
685
+ */
686
+
687
+ interface AdoptionReport {
688
+ sessionCount: number;
689
+ /** Sessions that invoked ≥1 skill (explicitly, via the Skill tool). */
690
+ sessionsWithSkill: number;
691
+ /** sessionsWithSkill / sessionCount (0 when no sessions). */
692
+ skillPenetration: number;
693
+ /** Explicit `Skill` tool invocations per skill name, corpus-wide. */
694
+ skillInvocations: Record<string, number>;
695
+ /** Total explicit `Skill` tool invocations. */
696
+ totalSkillInvocations: number;
697
+ /** Subagent spawns per subagent type (from Task/Agent tool spans). */
698
+ subagentSpawns: Record<string, number>;
699
+ /** Total subagent spawns. */
700
+ totalSubagentSpawns: number;
701
+ /** Sessions that spawned ≥1 subagent. */
702
+ sessionsWithSubagent: number;
703
+ /** Loop-dispatched skill runs per skill, read from `.evolve/skill-runs.jsonl`
704
+ * (NOT visible at trace level — counted separately to avoid silent zeros). */
705
+ loopDispatchedRuns: Record<string, number>;
706
+ /** Total loop-dispatched skill runs. */
707
+ totalLoopDispatchedRuns: number;
708
+ /** `.evolve/skill-runs.jsonl` files that were read. */
709
+ skillRunFilesRead: number;
710
+ }
711
+ /**
712
+ * Count loop-dispatched skill runs from a `.evolve/skill-runs.jsonl` file's raw
713
+ * contents. Each line records one or more skills under `skills` (array) or
714
+ * `skill` (string) — the schema varies across producers, so accept both.
715
+ */
716
+ declare function countSkillRunsJsonl(raw: string): Record<string, number>;
717
+ interface AdoptionOptions {
718
+ /** Session cwds to probe for `.evolve/skill-runs.jsonl`. The CLI passes the
719
+ * cwds of the analyzed sessions. */
720
+ cwds?: readonly string[];
721
+ }
722
+ declare function analyzeAdoption(spans: readonly OtlpSpan[], opts?: AdoptionOptions): Promise<AdoptionReport>;
723
+
500
724
  /**
501
725
  * Project normalized `OtlpSpan[]` onto agent-eval's runtime trace store.
502
726
  *
@@ -526,10 +750,9 @@ declare function toRuntimeStore(spans: readonly OtlpSpan[]): Promise<RuntimeTrac
526
750
  * LLM, model-agnostic). Supply `ai` to add the agentic RLM kinds
527
751
  * (failure-mode / knowledge-gap / knowledge-poisoning / improvement).
528
752
  *
529
- * The written OTLP file is the artifact our pipeline reads. External engines can
530
- * analyze it too: HALO needs canonical OpenInference, so `--analyzer halo`
531
- * converts it first (see external.ts `toCanonicalOpenInference`) — analysis is
532
- * never locked to one engine.
753
+ * The written file is canonical OpenInference (see otlp.ts), so it feeds our
754
+ * analysts AND external engines directly — `--analyzer halo` runs HALO over the
755
+ * same artifact, no conversion. Analysis is never locked to one engine.
533
756
  */
534
757
 
535
758
  interface AnalyzeOptions {
@@ -557,6 +780,94 @@ interface AnalyzeResult {
557
780
  }
558
781
  declare function analyzeSpans(spans: readonly OtlpSpan[], opts?: AnalyzeOptions): Promise<AnalyzeResult>;
559
782
 
783
+ interface PolicyEvidenceToolSummary {
784
+ readonly name: string;
785
+ readonly calls: number;
786
+ readonly errors: number;
787
+ }
788
+ interface PolicyEvidenceLoopSummary {
789
+ readonly toolName: string;
790
+ readonly occurrences: number;
791
+ }
792
+ interface PolicyEvidenceRecord {
793
+ readonly schemaVersion: 1;
794
+ readonly kind: 'traces.policy_evidence.session';
795
+ readonly generatedAt: string;
796
+ readonly session: {
797
+ readonly harness: string;
798
+ readonly sessionId: string;
799
+ readonly path: string;
800
+ readonly cwd: string | null;
801
+ readonly mtimeMs: number;
802
+ };
803
+ readonly repo: {
804
+ readonly subjectKey?: string;
805
+ readonly repository?: string;
806
+ readonly branch?: string;
807
+ readonly commit?: string;
808
+ readonly cwd?: string;
809
+ };
810
+ readonly metrics: {
811
+ readonly spanCount: number;
812
+ readonly llmTurnCount: number;
813
+ readonly toolCallCount: number;
814
+ readonly erroredToolCallCount: number;
815
+ readonly inputTokens: number;
816
+ readonly outputTokens: number;
817
+ readonly models: readonly string[];
818
+ readonly tools: readonly PolicyEvidenceToolSummary[];
819
+ readonly firstSpanAt: string | null;
820
+ readonly lastSpanAt: string | null;
821
+ };
822
+ readonly signals: {
823
+ readonly stuckLoopCount: number;
824
+ readonly affectedRunRatio: number;
825
+ readonly stuckLoops: readonly PolicyEvidenceLoopSummary[];
826
+ readonly stuckLoopsOmitted: number;
827
+ readonly toolErrorRate: number;
828
+ };
829
+ readonly provenance: {
830
+ readonly source: 'traces';
831
+ readonly evidenceKind: 'session-summary';
832
+ readonly otlpPath?: string;
833
+ readonly notCampaignCell: true;
834
+ readonly note: string;
835
+ };
836
+ }
837
+ interface BuildPolicyEvidenceOptions {
838
+ readonly generatedAt?: string;
839
+ readonly minLoopOccurrences?: number;
840
+ readonly maxLoopExamples?: number;
841
+ readonly otlpPath?: string;
842
+ }
843
+ interface CollectPolicyEvidenceOptions extends ScanOptions, BuildPolicyEvidenceOptions {
844
+ }
845
+ declare function buildPolicyEvidenceRecord(ref: SessionRef, spans: readonly OtlpSpan[], opts?: BuildPolicyEvidenceOptions): Promise<PolicyEvidenceRecord>;
846
+ declare function collectPolicyEvidence(opts: CollectPolicyEvidenceOptions): Promise<PolicyEvidenceRecord[]>;
847
+ declare function serializePolicyEvidence(records: readonly PolicyEvidenceRecord[]): string;
848
+ declare function writePolicyEvidenceFile(records: readonly PolicyEvidenceRecord[], outPath?: string): Promise<string>;
849
+
850
+ type JsonObject = Record<string, unknown>;
851
+ type TraceEvidenceInputFormat = 'policy-evidence' | 'sandbox-events' | 'openinference';
852
+ type TraceEvidenceFormatOption = TraceEvidenceInputFormat | 'auto';
853
+ interface TraceEvidenceExportOptions {
854
+ readonly format?: TraceEvidenceFormatOption;
855
+ readonly sourcePath?: string;
856
+ readonly attributes?: JsonObject;
857
+ }
858
+ interface TraceEvidenceExportResult {
859
+ readonly format: TraceEvidenceInputFormat;
860
+ readonly spans: OtlpSpan[];
861
+ readonly redactionCount: number;
862
+ readonly redactionsByRule: Record<string, number>;
863
+ }
864
+ declare function exportTraceEvidenceRows(rows: readonly unknown[], opts?: TraceEvidenceExportOptions, wrapper?: JsonObject): TraceEvidenceExportResult;
865
+ declare function exportTraceEvidenceText(text: string, opts?: TraceEvidenceExportOptions): TraceEvidenceExportResult;
866
+ declare function exportTraceEvidenceFile(inputPath: string, opts?: TraceEvidenceExportOptions): Promise<TraceEvidenceExportResult>;
867
+ declare function writeTraceEvidenceExportFile(inputPath: string, outPath?: string, opts?: TraceEvidenceExportOptions): Promise<TraceEvidenceExportResult & {
868
+ path: string;
869
+ }>;
870
+
560
871
  /**
561
872
  * External-tool adapters: run analysis engines and PII scrubbers that `traces`
562
873
  * does NOT bundle. Each is a thin command adapter over a shared subprocess
@@ -611,20 +922,11 @@ declare function commandAnalyzer(spec: {
611
922
  parse?: (stdout: string) => AnalystFinding[] | undefined;
612
923
  timeoutMs?: number;
613
924
  }): ExternalAnalyzer;
614
- /** Convert our OTLP-JSONL (the flat shape our pipeline reads) into the canonical
615
- * OpenInference span schema HALO's `SpanRecord` requires: top-level `kind`,
616
- * `resource`, `scope`, and a string (never null) `parent_span_id`. Our own
617
- * writer keeps the simpler shape for the agent-eval reader; this is the bridge
618
- * to OpenInference consumers. Input + output are JSONL strings (one span/line). */
619
- declare function toCanonicalOpenInference(otlpJsonl: string, opts?: {
620
- service?: string;
621
- scopeName?: string;
622
- }): string;
623
- /** HALO (github.com/context-labs/halo) over the OTLP artifact. HALO requires
624
- * canonical OpenInference, so this converts our OTLP to a `<path>.halo.jsonl`
625
- * first, then runs `halo <file> -p <prompt> [-m <model>]`. Install HALO yourself
626
- * and configure its LLM provider (it uses the OpenAI client — `OPENAI_BASE_URL`
627
- * / `OPENAI_API_KEY`); this just drives it. */
925
+ /** HALO (github.com/context-labs/halo) over the OTLP artifact: `halo <file> -p
926
+ * <prompt> [-m <model>]`. Our `serializeSpans` already emits canonical
927
+ * OpenInference, so HALO reads the artifact directly — no conversion. Install
928
+ * HALO yourself and configure its LLM provider (it uses the OpenAI client —
929
+ * `OPENAI_BASE_URL` / `OPENAI_API_KEY`); this just drives it. */
628
930
  declare function haloAnalyzer(opts?: {
629
931
  command?: string;
630
932
  defaultPrompt?: string;
@@ -867,4 +1169,4 @@ interface ExecuteOptions {
867
1169
  /** Send the NEW items (or, on dryRun, write the redacted OTLP that would send). */
868
1170
  declare function executeUpload(plan: UploadPlan, opts?: ExecuteOptions): Promise<UploadResult>;
869
1171
 
870
- export { ATTR, AmpAdapter, type AnalyzeOptions, type AnalyzeResult, CODING_REDACTION_RULES, CONTENT_CAP, ClaudeAdapter, CodexAdapter, type CollectOptions, CopilotAdapter, DEFAULT_HARNESS, type ExecuteOptions, type ExternalAnalysisResult, type ExternalAnalyzer, FactoryAdapter, ForgeAdapter, GeminiAdapter, type HarnessTraceAdapter, INGEST_SOURCE_CLI, type LocateOptions, type ObservedLoop, type ObserverOptions, OpencodeAdapter, type OtlpSpan, type OtlpSpanKind, type OtlpStatusCode, PiAdapter, type PipelineOptions, type PipelineReport, type PlanOptions, QwenAdapter, type Redactor, type RunResult, type RuntimeTrace, type ScanOptions, type ScannedSession, type SessionBatch, type SessionRef, type SpanInput, type SpanRedaction, TRACES_REDACTION_RULES, type UploadBackend, type UploadItem, type UploadPlan, type UploadRecord, type UploadResult, type UploadState, alreadyUploaded, analyzeSpans, applyRedactor, capText, collectSessions, commandAnalyzer, commandRedactor, executeUpload, haloAnalyzer, knownHarnesses, listAdapters, loadState, parseIsoToEpochMs, parseSince, planUpload, redactSpans, resolveAdapter, runCommand, runExternalAnalyzers, runPipelines, saveState, scanSessions, selectAdapters, serializeSpans, sessionHash, span, toCanonicalOpenInference, toRuntimeStore, toTraceSpanEvents, uploadKey, userPromptSpan, watchSessions, writeOtlpFile };
1172
+ export { ACTOR_ATTR, ATTR, type Actor, type AdoptionOptions, type AdoptionReport, AmpAdapter, type AnalyzeOptions, type AnalyzeResult, type BuildPolicyEvidenceOptions, CODING_REDACTION_RULES, CONTENT_CAP, CORRECTIVE_REACTIONS, ClaudeAdapter, CodexAdapter, type CollectOptions, type CollectPolicyEvidenceOptions, CopilotAdapter, DEFAULT_HARNESS, type ExecuteOptions, type ExternalAnalysisResult, type ExternalAnalyzer, FactoryAdapter, ForgeAdapter, GeminiAdapter, type HarnessTraceAdapter, INGEST_SOURCE_CLI, type LocateOptions, type ObservedLoop, type ObserverOptions, OpencodeAdapter, type OtlpSpan, type OtlpSpanKind, type OtlpStatusCode, PiAdapter, type PipelineOptions, type PipelineReport, type PlanOptions, type PolicyEvidenceLoopSummary, type PolicyEvidenceRecord, type PolicyEvidenceToolSummary, QwenAdapter, REACTIONS, type Reaction, type ReactionReport, type ReactionSessionReport, type Redactor, type RepoAttrs, type RunResult, type RuntimeTrace, type ScanOptions, type ScannedSession, type SessionBatch, type SessionRef, type SpanInput, type SpanRedaction, TRACES_REDACTION_RULES, type TraceEvidenceExportOptions, type TraceEvidenceExportResult, type TraceEvidenceFormatOption, type TraceEvidenceInputFormat, type TriggerPair, type UploadBackend, type UploadItem, type UploadPlan, type UploadRecord, type UploadResult, type UploadState, type UserPromptInput, alreadyUploaded, analyzeAdoption, analyzeReactions, analyzeSpans, applyRedactor, buildPolicyEvidenceRecord, capText, classifyReaction, claudeActor, codexActor, collectPolicyEvidence, collectSessions, commandAnalyzer, commandRedactor, countSkillRunsJsonl, executeUpload, exportTraceEvidenceFile, exportTraceEvidenceRows, exportTraceEvidenceText, haloAnalyzer, knownHarnesses, listAdapters, loadState, looksLikeAgentPrompt, normalizeRemote, parseIsoToEpochMs, parseSession, parseSince, planUpload, redactSpans, resolveAdapter, resolveRepoAttrs, runCommand, runExternalAnalyzers, runPipelines, saveState, scanSessions, selectAdapters, serializePolicyEvidence, serializeSpans, sessionHash, span, stampRepoAttrs, textIsSynthetic, toOpenInferenceSpan, toRuntimeStore, toTraceSpanEvents, uploadKey, userPromptSpan, watchSessions, writeOtlpFile, writePolicyEvidenceFile, writeTraceEvidenceExportFile };
package/dist/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import {
2
+ ACTOR_ATTR,
2
3
  ATTR,
3
4
  AmpAdapter,
4
5
  CODING_REDACTION_RULES,
5
6
  CONTENT_CAP,
7
+ CORRECTIVE_REACTIONS,
6
8
  ClaudeAdapter,
7
9
  CodexAdapter,
8
10
  CopilotAdapter,
@@ -14,40 +16,61 @@ import {
14
16
  OpencodeAdapter,
15
17
  PiAdapter,
16
18
  QwenAdapter,
19
+ REACTIONS,
17
20
  TRACES_REDACTION_RULES,
18
21
  alreadyUploaded,
22
+ analyzeAdoption,
23
+ analyzeReactions,
19
24
  analyzeSpans,
20
25
  applyRedactor,
26
+ buildPolicyEvidenceRecord,
21
27
  capText,
28
+ classifyReaction,
29
+ claudeActor,
30
+ codexActor,
31
+ collectPolicyEvidence,
22
32
  commandAnalyzer,
23
33
  commandRedactor,
34
+ countSkillRunsJsonl,
24
35
  executeUpload,
36
+ exportTraceEvidenceFile,
37
+ exportTraceEvidenceRows,
38
+ exportTraceEvidenceText,
25
39
  haloAnalyzer,
26
40
  knownHarnesses,
27
41
  listAdapters,
28
42
  loadState,
43
+ looksLikeAgentPrompt,
44
+ normalizeRemote,
29
45
  parseIsoToEpochMs,
46
+ parseSession,
30
47
  parseSince,
31
48
  planUpload,
32
49
  redactSpans,
33
50
  resolveAdapter,
51
+ resolveRepoAttrs,
34
52
  runCommand,
35
53
  runExternalAnalyzers,
36
54
  runPipelines,
37
55
  saveState,
38
56
  scanSessions,
39
57
  selectAdapters,
58
+ serializePolicyEvidence,
40
59
  serializeSpans,
41
60
  sessionHash,
42
61
  span,
43
- toCanonicalOpenInference,
62
+ stampRepoAttrs,
63
+ textIsSynthetic,
64
+ toOpenInferenceSpan,
44
65
  toRuntimeStore,
45
66
  toTraceSpanEvents,
46
67
  uploadKey,
47
68
  userPromptSpan,
48
69
  watchSessions,
49
- writeOtlpFile
50
- } from "./chunk-Q56AP2EY.js";
70
+ writeOtlpFile,
71
+ writePolicyEvidenceFile,
72
+ writeTraceEvidenceExportFile
73
+ } from "./chunk-D5OMTM4S.js";
51
74
 
52
75
  // src/collect.ts
53
76
  async function collectSessions(opts = {}) {
@@ -72,11 +95,13 @@ import {
72
95
  import { createHostedClient, hostedClientFromEnv } from "@tangle-network/agent-eval/hosted";
73
96
  import { DEFAULT_REDACTION_RULES, redactString, redactValue } from "@tangle-network/agent-eval/traces";
74
97
  export {
98
+ ACTOR_ATTR,
75
99
  ATTR,
76
100
  AmpAdapter,
77
101
  AnalystRegistry,
78
102
  CODING_REDACTION_RULES,
79
103
  CONTENT_CAP,
104
+ CORRECTIVE_REACTIONS,
80
105
  ClaudeAdapter,
81
106
  CodexAdapter,
82
107
  CopilotAdapter,
@@ -89,44 +114,65 @@ export {
89
114
  OpencodeAdapter,
90
115
  PiAdapter,
91
116
  QwenAdapter,
117
+ REACTIONS,
92
118
  TRACES_REDACTION_RULES,
93
119
  alreadyUploaded,
120
+ analyzeAdoption,
121
+ analyzeReactions,
94
122
  analyzeSpans,
95
123
  applyRedactor,
96
124
  buildDefaultAnalystRegistry,
125
+ buildPolicyEvidenceRecord,
97
126
  capText,
127
+ classifyReaction,
128
+ claudeActor,
129
+ codexActor,
130
+ collectPolicyEvidence,
98
131
  collectSessions,
99
132
  commandAnalyzer,
100
133
  commandRedactor,
134
+ countSkillRunsJsonl,
101
135
  createHostedClient,
102
136
  executeUpload,
137
+ exportTraceEvidenceFile,
138
+ exportTraceEvidenceRows,
139
+ exportTraceEvidenceText,
103
140
  haloAnalyzer,
104
141
  hostedClientFromEnv,
105
142
  knownHarnesses,
106
143
  listAdapters,
107
144
  loadState,
145
+ looksLikeAgentPrompt,
108
146
  makeFinding,
147
+ normalizeRemote,
109
148
  parseIsoToEpochMs,
149
+ parseSession,
110
150
  parseSince,
111
151
  planUpload,
112
152
  redactSpans,
113
153
  redactString,
114
154
  redactValue,
115
155
  resolveAdapter,
156
+ resolveRepoAttrs,
116
157
  runCommand,
117
158
  runExternalAnalyzers,
118
159
  runPipelines,
119
160
  saveState,
120
161
  scanSessions,
121
162
  selectAdapters,
163
+ serializePolicyEvidence,
122
164
  serializeSpans,
123
165
  sessionHash,
124
166
  span,
125
- toCanonicalOpenInference,
167
+ stampRepoAttrs,
168
+ textIsSynthetic,
169
+ toOpenInferenceSpan,
126
170
  toRuntimeStore,
127
171
  toTraceSpanEvents,
128
172
  uploadKey,
129
173
  userPromptSpan,
130
174
  watchSessions,
131
- writeOtlpFile
175
+ writeOtlpFile,
176
+ writePolicyEvidenceFile,
177
+ writeTraceEvidenceExportFile
132
178
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/traces",
3
- "version": "0.7.0",
3
+ "version": "0.8.5",
4
4
  "description": "Point it at your coding-agent session traces (Claude Code, Codex, OpenCode, Gemini, Pi, …) and get failure-mode + efficiency findings. CLI + SDK over the @tangle-network/agent-eval analyst suite — observe live sessions, run your own analysts, redact, and upload to the Tangle Intelligence Platform.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -22,7 +22,6 @@
22
22
  "llm",
23
23
  "coding-agent"
24
24
  ],
25
- "packageManager": "pnpm@10.33.4",
26
25
  "main": "./dist/index.js",
27
26
  "types": "./dist/index.d.ts",
28
27
  "exports": {
@@ -42,23 +41,23 @@
42
41
  "engines": {
43
42
  "node": ">=22"
44
43
  },
45
- "scripts": {
46
- "dev": "tsx src/cli.ts",
47
- "build": "tsup src/index.ts src/cli.ts --format esm --target node22 --clean --dts",
48
- "test": "vitest run",
49
- "test:watch": "vitest",
50
- "typecheck": "tsc --noEmit",
51
- "prepublishOnly": "pnpm build"
52
- },
53
44
  "dependencies": {
54
45
  "@ax-llm/ax": "^19.0.45",
55
- "@tangle-network/agent-eval": "0.94.0"
46
+ "@tangle-network/agent-eval": "^0.99.0"
56
47
  },
57
48
  "devDependencies": {
58
49
  "@types/node": "^22.0.0",
59
50
  "tsup": "^8.0.0",
60
51
  "tsx": "^4.19.0",
61
52
  "typescript": "^5.7.0",
62
- "vitest": "^2.0.0"
53
+ "vite": "^8.1.2",
54
+ "vitest": "^4.1.9"
55
+ },
56
+ "scripts": {
57
+ "dev": "tsx src/cli.ts",
58
+ "build": "tsup src/index.ts src/cli.ts --format esm --target node22 --clean --dts",
59
+ "test": "vitest run",
60
+ "test:watch": "vitest",
61
+ "typecheck": "tsc --noEmit"
63
62
  }
64
- }
63
+ }