Skip to content

Commit 41e5248

Browse files
jamesadevineCopilot
andcommitted
feat: plumb agent_name and agent_stats through ExecutionContext
- Add agent_name: Option<String> and agent_stats: Option<AgentStats> to ExecutionContext - Plumb front_matter.name to ctx.agent_name in main.rs execute handler - Load otel.jsonl from safe_output_dir, parse into ctx.agent_stats (non-fatal if missing — just logs debug/warn) - Add OTel env vars to base.yml AWF step (always-on: COPILOT_OTEL_ENABLED, COPILOT_OTEL_FILE_EXPORTER_PATH, COPILOT_OTEL_EXPORTER_TYPE) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent e8154bd commit 41e5248

7 files changed

Lines changed: 72 additions & 0 deletions

File tree

src/execute.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,8 @@ mod tests {
514514
repository_id: None,
515515
repository_name: None,
516516
allowed_repositories: HashMap::new(),
517+
agent_name: None,
518+
agent_stats: None,
517519
};
518520

519521
let result = execute_safe_output(&entry, &ctx).await;
@@ -546,6 +548,8 @@ mod tests {
546548
repository_id: None,
547549
repository_name: None,
548550
allowed_repositories: HashMap::new(),
551+
agent_name: None,
552+
agent_stats: None,
549553
};
550554

551555
let result = execute_safe_output(&entry, &ctx).await;
@@ -694,6 +698,8 @@ mod tests {
694698
repository_id: None,
695699
repository_name: None,
696700
allowed_repositories: HashMap::new(),
701+
agent_name: None,
702+
agent_stats: None,
697703
};
698704

699705
let result = execute_safe_output(&entry, &ctx).await;
@@ -736,6 +742,8 @@ mod tests {
736742
repository_id: None,
737743
repository_name: None,
738744
allowed_repositories: HashMap::new(),
745+
agent_name: None,
746+
agent_stats: None,
739747
};
740748

741749
let result = execute_safe_output(&entry, &ctx).await;
@@ -778,6 +786,8 @@ mod tests {
778786
repository_id: None,
779787
repository_name: None,
780788
allowed_repositories: HashMap::new(),
789+
agent_name: None,
790+
agent_stats: None,
781791
};
782792

783793
let result = execute_safe_output(&entry, &ctx).await;
@@ -825,6 +835,8 @@ mod tests {
825835
repository_id: None,
826836
repository_name: None,
827837
allowed_repositories: HashMap::new(),
838+
agent_name: None,
839+
agent_stats: None,
828840
};
829841

830842
let results = execute_safe_outputs(temp_dir.path(), &ctx).await;
@@ -1031,6 +1043,8 @@ mod tests {
10311043
repository_id: None,
10321044
repository_name: None,
10331045
allowed_repositories: HashMap::new(),
1046+
agent_name: None,
1047+
agent_stats: None,
10341048
};
10351049

10361050
let results = execute_safe_outputs(temp_dir.path(), &ctx).await;
@@ -1074,6 +1088,8 @@ mod tests {
10741088
repository_id: None,
10751089
repository_name: None,
10761090
allowed_repositories: HashMap::new(),
1091+
agent_name: None,
1092+
agent_stats: None,
10771093
};
10781094

10791095
let results = execute_safe_outputs(temp_dir.path(), &ctx).await.unwrap();

src/main.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,29 @@ async fn main() -> Result<()> {
216216
ctx.working_directory = safe_output_dir.clone();
217217
ctx.tool_configs = front_matter.safe_outputs.clone();
218218
ctx.allowed_repositories = allowed_repositories;
219+
ctx.agent_name = Some(front_matter.name.clone());
220+
221+
// Load agent stats from OTel JSONL if available
222+
let otel_path = safe_output_dir.join(agent_stats::OTEL_FILENAME);
223+
if otel_path.exists() {
224+
match agent_stats::AgentStats::from_otel_file(&otel_path, &front_matter.name)
225+
.await
226+
{
227+
Ok(stats) => {
228+
log::info!(
229+
"Agent stats: {} input / {} output tokens, {}s duration, {} tool calls, {} turns",
230+
stats.input_tokens, stats.output_tokens,
231+
stats.duration_seconds as u64, stats.tool_calls, stats.turns
232+
);
233+
ctx.agent_stats = Some(stats);
234+
}
235+
Err(e) => {
236+
log::warn!("Failed to parse OTel stats file: {}", e);
237+
}
238+
}
239+
} else {
240+
log::debug!("No OTel stats file found at {}", otel_path.display());
241+
}
219242

220243
let results = execute::execute_safe_outputs(&safe_output_dir, &ctx).await?;
221244

src/safeoutputs/create_wiki_page.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,8 @@ wiki-name: "MyProject.wiki"
668668
repository_id: None,
669669
repository_name: None,
670670
allowed_repositories: std::collections::HashMap::new(),
671+
agent_name: None,
672+
agent_stats: None,
671673
};
672674

673675
// wiki-name not in config → should return Err
@@ -731,6 +733,8 @@ wiki-name: "MyProject.wiki"
731733
repository_id: None,
732734
repository_name: None,
733735
allowed_repositories: HashMap::new(),
736+
agent_name: None,
737+
agent_stats: None,
734738
};
735739

736740
let outcome = result.execute_impl(&ctx).await.unwrap();
@@ -769,6 +773,8 @@ wiki-name: "MyProject.wiki"
769773
repository_id: None,
770774
repository_name: None,
771775
allowed_repositories: HashMap::new(),
776+
agent_name: None,
777+
agent_stats: None,
772778
};
773779

774780
let outcome = result.execute_impl(&ctx).await.unwrap();
@@ -807,6 +813,8 @@ wiki-name: "MyProject.wiki"
807813
repository_id: None,
808814
repository_name: None,
809815
allowed_repositories: HashMap::new(),
816+
agent_name: None,
817+
agent_stats: None,
810818
};
811819

812820
// The GET will fail (network unreachable with a fake host), so the

src/safeoutputs/result.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ pub struct ExecutionContext {
5656
/// Allowed repositories for PRs: "self" + checkout list aliases
5757
/// Maps alias to ADO repo name (e.g., "other-repo" -> "org/other-repo")
5858
pub allowed_repositories: HashMap<String, String>,
59+
/// Agent name from front matter (for display in stats blocks)
60+
pub agent_name: Option<String>,
61+
/// Agent execution statistics parsed from OTel JSONL
62+
pub agent_stats: Option<crate::agent_stats::AgentStats>,
5963
}
6064

6165
impl ExecutionContext {
@@ -109,6 +113,8 @@ impl Default for ExecutionContext {
109113
repository_id: std::env::var("BUILD_REPOSITORY_ID").ok(),
110114
repository_name: std::env::var("BUILD_REPOSITORY_NAME").ok(),
111115
allowed_repositories: HashMap::new(),
116+
agent_name: None,
117+
agent_stats: None,
112118
}
113119
}
114120
}

src/safeoutputs/update_wiki_page.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,8 @@ wiki-name: "MyProject.wiki"
638638
repository_id: None,
639639
repository_name: None,
640640
allowed_repositories: std::collections::HashMap::new(),
641+
agent_name: None,
642+
agent_stats: None,
641643
};
642644

643645
// wiki-name not in config → should return Err
@@ -701,6 +703,8 @@ wiki-name: "MyProject.wiki"
701703
repository_id: None,
702704
repository_name: None,
703705
allowed_repositories: HashMap::new(),
706+
agent_name: None,
707+
agent_stats: None,
704708
};
705709

706710
let outcome = result.execute_impl(&ctx).await.unwrap();
@@ -739,6 +743,8 @@ wiki-name: "MyProject.wiki"
739743
repository_id: None,
740744
repository_name: None,
741745
allowed_repositories: HashMap::new(),
746+
agent_name: None,
747+
agent_stats: None,
742748
};
743749

744750
let outcome = result.execute_impl(&ctx).await.unwrap();
@@ -777,6 +783,8 @@ wiki-name: "MyProject.wiki"
777783
repository_id: None,
778784
repository_name: None,
779785
allowed_repositories: HashMap::new(),
786+
agent_name: None,
787+
agent_stats: None,
780788
};
781789

782790
// The GET will fail (network unreachable with a fake host), so the

src/safeoutputs/update_work_item.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,8 @@ target: 42
716716
repository_id: None,
717717
repository_name: None,
718718
allowed_repositories: HashMap::new(),
719+
agent_name: None,
720+
agent_stats: None,
719721
};
720722

721723
let exec_result = result.execute_sanitized(&ctx).await;
@@ -765,6 +767,8 @@ target: 42
765767
repository_id: None,
766768
repository_name: None,
767769
allowed_repositories: HashMap::new(),
770+
agent_name: None,
771+
agent_stats: None,
768772
};
769773

770774
let exec_result = result.execute_sanitized(&ctx).await.unwrap();
@@ -810,6 +814,8 @@ target: 42
810814
repository_id: None,
811815
repository_name: None,
812816
allowed_repositories: HashMap::new(),
817+
agent_name: None,
818+
agent_stats: None,
813819
};
814820

815821
let exec_result = result.execute_sanitized(&ctx).await.unwrap();
@@ -857,6 +863,8 @@ target: 42
857863
repository_id: None,
858864
repository_name: None,
859865
allowed_repositories: HashMap::new(),
866+
agent_name: None,
867+
agent_stats: None,
860868
};
861869

862870
let exec_result = result.execute_sanitized(&ctx).await.unwrap();

templates/base.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,9 @@ jobs:
336336
{{ copilot_ado_env }}
337337
GITHUB_TOKEN: $(GITHUB_TOKEN)
338338
GITHUB_READ_ONLY: 1
339+
COPILOT_OTEL_ENABLED: "true"
340+
COPILOT_OTEL_EXPORTER_TYPE: "file"
341+
COPILOT_OTEL_FILE_EXPORTER_PATH: "/tmp/awf-tools/staging/otel.jsonl"
339342
340343
- bash: |
341344
# Copy safe outputs from /tmp back to staging for artifact publish

0 commit comments

Comments
 (0)