Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
655f4c2
refactor: share provider extraction strategies
yczhang-nv Jun 26, 2026
a82bdff
docs: clarify response extraction contract
yczhang-nv Jun 26, 2026
727eafc
docs: note extraction shim migration
yczhang-nv Jun 26, 2026
d25aaae
test: assert adapter fallback boundary
yczhang-nv Jun 26, 2026
0bfc124
test: cover agent payload extraction
yczhang-nv Jun 26, 2026
d879ba6
fix: avoid promoting user email metadata
yczhang-nv Jun 26, 2026
ad1fbb8
test: cover anthropic hinted request decode
yczhang-nv Jun 26, 2026
fb9258f
fix: avoid path metadata promotion
yczhang-nv Jun 26, 2026
20816ae
fix: normalize requests with provider hints
yczhang-nv Jun 26, 2026
720e19e
refactor: clarify extraction naming
yczhang-nv Jun 26, 2026
2e3cb6f
fix: restrict anthropic provider hints
yczhang-nv Jun 26, 2026
359ff7e
test: assert cwd payload preservation
yczhang-nv Jun 26, 2026
afada10
refactor: share CLI JSON extraction primitives
yczhang-nv Jun 30, 2026
72d90ad
refactor: split CLI extraction strategies
yczhang-nv Jun 30, 2026
aab6b72
Merge remote-tracking branch 'upstream/main' into refactor/shared-ext…
yczhang-nv Jun 30, 2026
9a8770b
docs: document CLI extraction contracts
yczhang-nv Jun 30, 2026
421423c
fix: stabilize extraction route fallbacks
yczhang-nv Jun 30, 2026
e53b663
Merge remote-tracking branch 'upstream/main' into refactor/shared-ext…
yczhang-nv Jun 30, 2026
d18d586
docs: clarify provider request extraction
yczhang-nv Jun 30, 2026
85822a9
refactor: model agent extractor deviations via trait defaults
yczhang-nv Jun 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion crates/cli/src/adapters/claude_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
use axum::http::HeaderMap;
use serde_json::{Value, json};

use crate::adapters::{AdapterOutcome, ClassificationRules, classify};
use crate::adapters::{
AdapterOutcome, CLAUDE_CODE_PAYLOAD_EXTRACTOR, ClassificationRules, classify,
};
use crate::model::{AgentKind, NormalizedEvent};

/// Normalizes Claude Code hook payloads and returns the hook response Claude expects.
Expand All @@ -18,6 +20,7 @@ pub(crate) fn adapt(payload: Value, headers: &HeaderMap) -> AdapterOutcome {
let events = classify(
&payload,
headers,
&CLAUDE_CODE_PAYLOAD_EXTRACTOR,
&ClassificationRules {
kind: AgentKind::ClaudeCode,
agent_start: &["SessionStart", "sessionStart", "session_start"],
Expand Down
3 changes: 2 additions & 1 deletion crates/cli/src/adapters/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use axum::http::HeaderMap;
use serde_json::{Value, json};

use crate::adapters::{AdapterOutcome, ClassificationRules, classify};
use crate::adapters::{AdapterOutcome, CODEX_PAYLOAD_EXTRACTOR, ClassificationRules, classify};
use crate::model::AgentKind;

/// Normalizes Codex hook payloads while leaving Codex hook control flow untouched.
Expand All @@ -16,6 +16,7 @@ pub(crate) fn adapt(payload: Value, headers: &HeaderMap) -> AdapterOutcome {
let events = classify(
&payload,
headers,
&CODEX_PAYLOAD_EXTRACTOR,
&ClassificationRules {
kind: AgentKind::Codex,
agent_start: &["sessionStart", "session_start", "agentStarted"],
Expand Down
3 changes: 2 additions & 1 deletion crates/cli/src/adapters/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use axum::http::HeaderMap;
use serde_json::{Value, json};

use crate::adapters::{AdapterOutcome, ClassificationRules, classify};
use crate::adapters::{AdapterOutcome, CURSOR_PAYLOAD_EXTRACTOR, ClassificationRules, classify};
use crate::model::{AgentKind, NormalizedEvent};

/// Normalizes Cursor hook payloads and returns Cursor-compatible continuation decisions.
Expand All @@ -16,6 +16,7 @@ pub(crate) fn adapt(payload: Value, headers: &HeaderMap) -> AdapterOutcome {
let events = classify(
&payload,
headers,
&CURSOR_PAYLOAD_EXTRACTOR,
&ClassificationRules {
kind: AgentKind::Cursor,
agent_start: &["sessionStart", "session_start"],
Expand Down
19 changes: 14 additions & 5 deletions crates/cli/src/adapters/hermes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ use axum::http::HeaderMap;
use serde_json::{Map, Value, json};

use crate::adapters::{
AdapterOutcome, ClassificationRules, classify, common_session_event, event_name, metadata,
normalize_name, session_id, value_at,
AdapterOutcome, ClassificationRules, HERMES_PAYLOAD_EXTRACTOR, classify, common_session_event,
event_name, metadata, normalize_name, session_id,
};
use crate::json_path::value_at;
use crate::model::{AgentKind, LlmEvent, NormalizedEvent};

/// Normalizes Hermes shell hook payloads without emitting control directives.
Expand All @@ -16,7 +17,7 @@ use crate::model::{AgentKind, LlmEvent, NormalizedEvent};
/// responses minimal and relies on the forwarder fail-open/fail-closed setting to decide whether
/// hook delivery problems affect the invoking agent.
pub(crate) fn adapt(payload: Value, headers: &HeaderMap) -> AdapterOutcome {
let event_name = event_name(&payload);
let event_name = event_name(&payload, &HERMES_PAYLOAD_EXTRACTOR);
let normalized = normalize_name(&event_name);
if normalized == "preapirequest" {
return AdapterOutcome {
Expand Down Expand Up @@ -64,6 +65,7 @@ pub(crate) fn adapt(payload: Value, headers: &HeaderMap) -> AdapterOutcome {
&payload,
headers,
AgentKind::Hermes,
&HERMES_PAYLOAD_EXTRACTOR,
))],
response: json!({}),
};
Expand All @@ -72,6 +74,7 @@ pub(crate) fn adapt(payload: Value, headers: &HeaderMap) -> AdapterOutcome {
let events = classify(
&payload,
headers,
&HERMES_PAYLOAD_EXTRACTOR,
&ClassificationRules {
kind: AgentKind::Hermes,
agent_start: &["on_session_start", "sessionStart"],
Expand All @@ -89,15 +92,21 @@ pub(crate) fn adapt(payload: Value, headers: &HeaderMap) -> AdapterOutcome {
}

fn hermes_llm_event(payload: &Value, headers: &HeaderMap, event_name: &str) -> LlmEvent {
let session_id = session_id(payload, headers);
let session_id = session_id(payload, headers, &HERMES_PAYLOAD_EXTRACTOR);
let api_call_id = hermes_api_call_id(payload, &session_id);
let provider = hermes_string_at(payload, "provider")
.or_else(|| hermes_string_at(payload, "api_mode"))
.unwrap_or_else(|| "hermes_api_request".to_string());
let model_name =
hermes_string_at(payload, "response_model").or_else(|| hermes_string_at(payload, "model"));
let payload_exact = hermes_payload_exact(payload, event_name);
let mut event_metadata = metadata(payload, headers, AgentKind::Hermes, event_name);
let mut event_metadata = metadata(
payload,
headers,
AgentKind::Hermes,
event_name,
&HERMES_PAYLOAD_EXTRACTOR,
);
if let Value::Object(ref mut object) = event_metadata {
object.insert("api_call_id".into(), json!(api_call_id.clone()));
object.insert("provider_payload_exact".into(), json!(payload_exact));
Expand Down
Loading
Loading