aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/next/website/src/content/docs/cli-reference.mdx6
-rw-r--r--docs/next/website/src/content/docs/socket-api.mdx15
-rw-r--r--src/api/schema.rs14
-rw-r--r--src/app/agents.rs1
-rw-r--r--src/app/creation.rs26
-rw-r--r--tests/api_ping.rs26
6 files changed, 85 insertions, 3 deletions
diff --git a/docs/next/website/src/content/docs/cli-reference.mdx b/docs/next/website/src/content/docs/cli-reference.mdx
index ed51ce1e..d79e34d0 100644
--- a/docs/next/website/src/content/docs/cli-reference.mdx
+++ b/docs/next/website/src/content/docs/cli-reference.mdx
@@ -129,9 +129,13 @@ herdr pane report-agent <pane_id> \
--state idle|working|blocked|unknown \
[--message TEXT] \
[--custom-status TEXT] \
- [--seq N]
+ [--seq N] \
+ [--agent-session-id ID] \
+ [--agent-session-path PATH]
```
+`pane get`, `pane list`, `agent get`, and `agent list` include a read-only `agent_session` object when an official integration has reported a native session reference. If no native session reference is stored, the field is omitted.
+
Report display-only pane metadata without taking over semantic state:
```bash
diff --git a/docs/next/website/src/content/docs/socket-api.mdx b/docs/next/website/src/content/docs/socket-api.mdx
index 3b12d928..382a3c62 100644
--- a/docs/next/website/src/content/docs/socket-api.mdx
+++ b/docs/next/website/src/content/docs/socket-api.mdx
@@ -163,6 +163,21 @@ Integrations report agent state with `pane.report_agent`.
`custom_status` is visual. It can show a short label like `indexing` without changing semantic behavior.
+Official integrations can also report a native session reference. `pane.get`, `pane.list`, `agent.get`, and `agent.list` expose a read-only `agent_session` object when Herdr has a stored native session reference:
+
+```json
+{
+ "agent_session": {
+ "source": "herdr:codex",
+ "agent": "codex",
+ "kind": "id",
+ "value": "..."
+ }
+}
+```
+
+If no native session reference is stored, the field is omitted.
+
Use `pane.report_metadata` when a user hook wants to customize presentation without taking over lifecycle state from a Herdr integration.
```json
diff --git a/src/api/schema.rs b/src/api/schema.rs
index aa7cbd3c..cd82f99f 100644
--- a/src/api/schema.rs
+++ b/src/api/schema.rs
@@ -803,6 +803,8 @@ pub struct AgentInfo {
pub custom_status: Option<String>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub state_labels: HashMap<String, String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub agent_session: Option<AgentSessionInfo>,
pub workspace_id: String,
pub tab_id: String,
pub pane_id: String,
@@ -834,10 +836,20 @@ pub struct PaneInfo {
pub custom_status: Option<String>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub state_labels: HashMap<String, String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub agent_session: Option<AgentSessionInfo>,
pub revision: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct AgentSessionInfo {
+ pub source: String,
+ pub agent: String,
+ pub kind: crate::agent_resume::AgentSessionRefKind,
+ pub value: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PaneReadResult {
pub pane_id: String,
pub workspace_id: String,
@@ -1402,6 +1414,7 @@ mod tests {
agent_status: AgentStatus::Unknown,
custom_status: None,
state_labels: HashMap::new(),
+ agent_session: None,
revision: 0,
},
worktree: WorktreeInfo {
@@ -1451,6 +1464,7 @@ mod tests {
agent_status: AgentStatus::Unknown,
custom_status: None,
state_labels: HashMap::new(),
+ agent_session: None,
revision: 0,
},
},
diff --git a/src/app/agents.rs b/src/app/agents.rs
index 8868fb9c..55ee15df 100644
--- a/src/app/agents.rs
+++ b/src/app/agents.rs
@@ -417,6 +417,7 @@ impl App {
agent_status: pane.agent_status,
custom_status: pane.custom_status,
state_labels: pane.state_labels,
+ agent_session: pane.agent_session,
workspace_id: pane.workspace_id,
tab_id: pane.tab_id,
pane_id: pane.pane_id,
diff --git a/src/app/creation.rs b/src/app/creation.rs
index aa727dd5..d483eb1a 100644
--- a/src/app/creation.rs
+++ b/src/app/creation.rs
@@ -295,6 +295,7 @@ impl App {
agent_status: pane_agent_status(terminal.state, pane.seen),
custom_status: presentation.custom_status,
state_labels: presentation.state_labels,
+ agent_session: terminal_agent_session_info(terminal),
revision: terminal.revision,
})
}
@@ -345,3 +346,28 @@ impl App {
}
}
}
+
+fn terminal_agent_session_info(
+ terminal: &crate::terminal::TerminalState,
+) -> Option<crate::api::schema::AgentSessionInfo> {
+ if let Some(authority) = terminal.hook_authority.as_ref() {
+ if let Some(session_ref) = authority.session_ref.as_ref() {
+ return Some(crate::api::schema::AgentSessionInfo {
+ source: authority.source.clone(),
+ agent: authority.agent_label.clone(),
+ kind: session_ref.kind,
+ value: session_ref.value.clone(),
+ });
+ }
+ }
+
+ terminal
+ .persisted_agent_session
+ .as_ref()
+ .map(|session| crate::api::schema::AgentSessionInfo {
+ source: session.source.clone(),
+ agent: session.agent.clone(),
+ kind: session.session_ref.kind,
+ value: session.session_ref.value.clone(),
+ })
+}
diff --git a/tests/api_ping.rs b/tests/api_ping.rs
index 239daeae..064bac13 100644
--- a/tests/api_ping.rs
+++ b/tests/api_ping.rs
@@ -1209,11 +1209,13 @@ fn pane_report_agent_updates_effective_state() {
thread::sleep(Duration::from_millis(100));
}
+ let session_path = base.join("pi-session.jsonl");
let hook = send_request(
&socket_path,
&format!(
- r#"{{"id":"req_hook_5","method":"pane.report_agent","params":{{"pane_id":"{}","source":"herdr:pi","agent":"pi","state":"working","message":"thinking"}}}}"#,
- pane_id
+ r#"{{"id":"req_hook_5","method":"pane.report_agent","params":{{"pane_id":"{}","source":"herdr:pi","agent":"pi","state":"working","message":"thinking","agent_session_path":"{}"}}}}"#,
+ pane_id,
+ session_path.display()
),
);
assert_eq!(hook["result"]["type"], "ok");
@@ -1227,6 +1229,16 @@ fn pane_report_agent_updates_effective_state() {
);
assert_eq!(pane["result"]["pane"]["agent"], "pi");
assert_eq!(pane["result"]["pane"]["agent_status"], "working");
+ assert_eq!(
+ pane["result"]["pane"]["agent_session"]["source"],
+ "herdr:pi"
+ );
+ assert_eq!(pane["result"]["pane"]["agent_session"]["agent"], "pi");
+ assert_eq!(pane["result"]["pane"]["agent_session"]["kind"], "path");
+ assert_eq!(
+ pane["result"]["pane"]["agent_session"]["value"],
+ session_path.display().to_string()
+ );
let metadata = send_request(
&socket_path,
@@ -1259,6 +1271,16 @@ fn pane_report_agent_updates_effective_state() {
r#"{"id":"req_hook_metadata_agent","method":"agent.get","params":{"target":"pi"}}"#,
);
assert_eq!(agent["result"]["agent"]["agent"], "pi");
+ assert_eq!(
+ agent["result"]["agent"]["agent_session"]["source"],
+ "herdr:pi"
+ );
+ assert_eq!(agent["result"]["agent"]["agent_session"]["agent"], "pi");
+ assert_eq!(agent["result"]["agent"]["agent_session"]["kind"], "path");
+ assert_eq!(
+ agent["result"]["agent"]["agent_session"]["value"],
+ session_path.display().to_string()
+ );
assert_eq!(agent["result"]["agent"]["title"], "Refactor auth");
assert_eq!(agent["result"]["agent"]["display_agent"], "Pi auth");
assert_eq!(agent["result"]["agent"]["custom_status"], "middleware");