@faithfulalabi/agent-lens 0.9.0 → 0.10.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.
@@ -2,7 +2,7 @@ import { asyncAgentLaunch, taskNotification } from '../transcript/agents.js';
2
2
  import { attachmentRecord } from '../transcript/attachments.js';
3
3
  import { contentBlocks, imageCount, resultText } from '../transcript/blocks.js';
4
4
  import { isHumanPrompt, MACHINERY_TAGS } from '../transcript/human.js';
5
- import { foldControlLines, foldSessionEnvelope, promptGroupId, toolDenialKind, turnDurationMs, } from '../transcript/line.js';
5
+ import { foldControlLines, foldSessionEnvelope, permissionDecision, promptGroupId, toolDenialKind, turnDurationMs, } from '../transcript/line.js';
6
6
  import { foldRequestGroup, groupByRequestId, modelOfRequestGroup, requestIdOf, } from '../transcript/usage.js';
7
7
  import { joinToolCalls, NO_INPUT, NO_WIRE_INPUT, toolInput, wireInput, } from './tools.js';
8
8
  import { wireInputOf } from '../transcript/wire.js';
@@ -137,6 +137,7 @@ export function runPipeline(lines, ctx) {
137
137
  text: output,
138
138
  is_error: block.is_error,
139
139
  denial: toolDenialKind(line),
140
+ decision: permissionDecision(line),
140
141
  launch: asyncAgentLaunch(line, output),
141
142
  ts: line.timestamp ?? '',
142
143
  result_offset: line.byte_offset,
@@ -49,8 +49,15 @@ function elapsedMs(call, result) {
49
49
  const ms = epochMs(result) - epochMs(call);
50
50
  return ms < 0 ? 0 : ms;
51
51
  }
52
+ function statedDenial(decision) {
53
+ if (decision === 'reject')
54
+ return true;
55
+ if (decision === 'accept')
56
+ return false;
57
+ return undefined;
58
+ }
52
59
  function statusOf(result) {
53
- if (result.denial !== undefined)
60
+ if (statedDenial(result.decision) ?? result.denial !== undefined)
54
61
  return 'denied';
55
62
  return result.is_error ? 'error' : 'ok';
56
63
  }
@@ -102,6 +109,10 @@ export function joinToolCalls(events, results, notifications, drift) {
102
109
  event.duration_ms = elapsedMs(event.ts, result.ts);
103
110
  event.duration_source = 'elapsed';
104
111
  event.status = statusOf(result);
112
+ if (result.decision !== undefined &&
113
+ statedDenial(result.decision) !== (result.denial !== undefined)) {
114
+ drift.notePermissionDecisionMismatch();
115
+ }
105
116
  if (event.name === 'Agent' && result.launch !== undefined) {
106
117
  backPatch(event, answers.get(event.id));
107
118
  continue;
@@ -12,6 +12,7 @@ export class DriftCounter {
12
12
  blockTypes = new Map();
13
13
  unjoinedToolUses = 0;
14
14
  sidecarAgentIdMismatches = 0;
15
+ permissionDecisionMismatches = 0;
15
16
  noteLine(line, knownFields) {
16
17
  for (const name of Object.keys(line)) {
17
18
  if (!knownFields.has(name))
@@ -30,8 +31,12 @@ export class DriftCounter {
30
31
  noteSidecarMismatch() {
31
32
  this.sidecarAgentIdMismatches += 1;
32
33
  }
34
+ notePermissionDecisionMismatch() {
35
+ this.permissionDecisionMismatches += 1;
36
+ }
33
37
  serialize() {
34
38
  return JSON.stringify({
39
+ permission_decision_mismatch: this.permissionDecisionMismatches === 0 ? undefined : this.permissionDecisionMismatches,
35
40
  sidecar_agent_id_mismatch: this.sidecarAgentIdMismatches === 0 ? undefined : this.sidecarAgentIdMismatches,
36
41
  unjoined_tool_uses: this.unjoinedToolUses === 0 ? undefined : this.unjoinedToolUses,
37
42
  unknown_block_types: bucket(this.blockTypes),
@@ -75,6 +75,7 @@ const LINE_TYPES = new Map([
75
75
  'classifierMetaLines',
76
76
  'toolEndsTurn',
77
77
  'toolDenialKind',
78
+ 'permissionDecision',
78
79
  'imagePasteIds',
79
80
  'serverClassifierContext',
80
81
  'turnOrigin',
@@ -264,6 +265,11 @@ export function promptGroupId(line) {
264
265
  export function toolDenialKind(line) {
265
266
  return str(line.raw.toolDenialKind, undefined);
266
267
  }
268
+ export function permissionDecision(line) {
269
+ if (line.raw.permissionDecision === undefined)
270
+ return undefined;
271
+ return str(obj(line.raw.permissionDecision, undefined)?.decision, '');
272
+ }
267
273
  export function turnDurationMs(line) {
268
274
  return line.kind === 'system' && line.subtype === 'turn_duration'
269
275
  ? num(line.raw.durationMs, undefined)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faithfulalabi/agent-lens",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Local-first agentic tracing platform: inspect everything your agent did in a session.",
5
5
  "type": "module",
6
6
  "license": "MIT",