feat: expose agent session refs in api
This commit is contained in:
parent
986e4a1776
commit
2d8b4e2db4
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,9 +836,19 @@ 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,
|
||||
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Reference in New Issue