fix(goose): propagate session_id across providers and MCP (#6584)
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
@@ -25,6 +25,7 @@ use goose::providers::{create, providers, retry_operation, RetryConfig};
|
||||
use goose::session::SessionType;
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
|
||||
// useful for light themes where there is no dicernible colour contrast between
|
||||
// cursor-selected and cursor-unselected items.
|
||||
@@ -682,8 +683,10 @@ pub async fn configure_provider_dialog() -> anyhow::Result<bool> {
|
||||
let models_res = {
|
||||
let temp_model_config = ModelConfig::new(&provider_meta.default_model)?;
|
||||
let temp_provider = create(provider_name, temp_model_config).await?;
|
||||
// Provider setup runs before any user session exists; use an ephemeral id.
|
||||
let session_id = Uuid::new_v4().to_string();
|
||||
retry_operation(&RetryConfig::default(), || async {
|
||||
temp_provider.fetch_recommended_models().await
|
||||
temp_provider.fetch_recommended_models(&session_id).await
|
||||
})
|
||||
.await
|
||||
};
|
||||
@@ -1655,9 +1658,11 @@ pub async fn handle_openrouter_auth() -> anyhow::Result<()> {
|
||||
|
||||
match create("openrouter", model_config).await {
|
||||
Ok(provider) => {
|
||||
// Simple test request
|
||||
// Config verification runs before any user session exists; use an ephemeral id.
|
||||
let session_id = Uuid::new_v4().to_string();
|
||||
let test_result = provider
|
||||
.complete(
|
||||
&session_id,
|
||||
"You are goose, an AI assistant.",
|
||||
&[Message::user().with_text("Say 'Configuration test successful!'")],
|
||||
&[],
|
||||
@@ -1733,8 +1738,11 @@ pub async fn handle_tetrate_auth() -> anyhow::Result<()> {
|
||||
|
||||
match create("tetrate", model_config).await {
|
||||
Ok(provider) => {
|
||||
// Config verification runs before any user session exists; use an ephemeral id.
|
||||
let session_id = Uuid::new_v4().to_string();
|
||||
let test_result = provider
|
||||
.complete(
|
||||
&session_id,
|
||||
"You are goose, an AI assistant.",
|
||||
&[Message::user().with_text("Say 'Configuration test successful!'")],
|
||||
&[],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! MockClient is a mock implementation of the McpClientTrait for testing purposes.
|
||||
//! add a tool you want to have around and then add the client to the extension router
|
||||
|
||||
use goose::agents::mcp_client::{Error, McpClientTrait, McpMeta};
|
||||
use goose::agents::mcp_client::{Error, McpClientTrait};
|
||||
use rmcp::{
|
||||
model::{
|
||||
CallToolResult, Content, ErrorData, GetPromptResult, ListPromptsResult,
|
||||
@@ -44,6 +44,7 @@ impl MockClient {
|
||||
impl McpClientTrait for MockClient {
|
||||
async fn list_resources(
|
||||
&self,
|
||||
_session_id: &str,
|
||||
_next_cursor: Option<String>,
|
||||
_cancel_token: CancellationToken,
|
||||
) -> Result<ListResourcesResult, Error> {
|
||||
@@ -60,6 +61,7 @@ impl McpClientTrait for MockClient {
|
||||
|
||||
async fn read_resource(
|
||||
&self,
|
||||
_session_id: &str,
|
||||
_uri: &str,
|
||||
_cancel_token: CancellationToken,
|
||||
) -> Result<ReadResourceResult, Error> {
|
||||
@@ -68,6 +70,7 @@ impl McpClientTrait for MockClient {
|
||||
|
||||
async fn list_tools(
|
||||
&self,
|
||||
_session_id: &str,
|
||||
_: Option<String>,
|
||||
_cancel_token: CancellationToken,
|
||||
) -> Result<ListToolsResult, Error> {
|
||||
@@ -92,9 +95,9 @@ impl McpClientTrait for MockClient {
|
||||
|
||||
async fn call_tool(
|
||||
&self,
|
||||
_session_id: &str,
|
||||
name: &str,
|
||||
arguments: Option<serde_json::Map<String, Value>>,
|
||||
_meta: McpMeta,
|
||||
_cancel_token: CancellationToken,
|
||||
) -> Result<CallToolResult, Error> {
|
||||
if let Some(handler) = self.handlers.get(name) {
|
||||
@@ -114,6 +117,7 @@ impl McpClientTrait for MockClient {
|
||||
|
||||
async fn list_prompts(
|
||||
&self,
|
||||
_session_id: &str,
|
||||
_next_cursor: Option<String>,
|
||||
_cancel_token: CancellationToken,
|
||||
) -> Result<ListPromptsResult, Error> {
|
||||
@@ -126,6 +130,7 @@ impl McpClientTrait for MockClient {
|
||||
|
||||
async fn get_prompt(
|
||||
&self,
|
||||
_session_id: &str,
|
||||
_name: &str,
|
||||
_arguments: Value,
|
||||
_cancel_token: CancellationToken,
|
||||
|
||||
@@ -193,15 +193,16 @@ pub enum PlannerResponseType {
|
||||
/// to the user's message. The response is either a plan or a clarifying
|
||||
/// question.
|
||||
pub async fn classify_planner_response(
|
||||
session_id: &str,
|
||||
message_text: String,
|
||||
provider: Arc<dyn Provider>,
|
||||
) -> Result<PlannerResponseType> {
|
||||
let prompt = format!("The text below is the output from an AI model which can either provide a plan or list of clarifying questions. Based on the text below, decide if the output is a \"plan\" or \"clarifying questions\".\n---\n{message_text}");
|
||||
|
||||
// Generate the description
|
||||
let message = Message::user().with_text(&prompt);
|
||||
let (result, _usage) = provider
|
||||
.complete(
|
||||
session_id,
|
||||
"Reply only with the classification label: \"plan\" or \"clarifying questions\"",
|
||||
&[message],
|
||||
&[],
|
||||
@@ -367,7 +368,7 @@ impl CliSession {
|
||||
&mut self,
|
||||
extension: Option<String>,
|
||||
) -> Result<HashMap<String, Vec<String>>> {
|
||||
let prompts = self.agent.list_extension_prompts().await;
|
||||
let prompts = self.agent.list_extension_prompts(&self.session_id).await;
|
||||
|
||||
// Early validation if filtering by extension
|
||||
if let Some(filter) = &extension {
|
||||
@@ -388,7 +389,7 @@ impl CliSession {
|
||||
}
|
||||
|
||||
pub async fn get_prompt_info(&mut self, name: &str) -> Result<Option<output::PromptInfo>> {
|
||||
let prompts = self.agent.list_extension_prompts().await;
|
||||
let prompts = self.agent.list_extension_prompts(&self.session_id).await;
|
||||
|
||||
// Find which extension has this prompt
|
||||
for (extension, prompt_list) in prompts {
|
||||
@@ -406,7 +407,11 @@ impl CliSession {
|
||||
}
|
||||
|
||||
pub async fn get_prompt(&mut self, name: &str, arguments: Value) -> Result<Vec<PromptMessage>> {
|
||||
Ok(self.agent.get_prompt(name, arguments).await?.messages)
|
||||
Ok(self
|
||||
.agent
|
||||
.get_prompt(&self.session_id, name, arguments)
|
||||
.await?
|
||||
.messages)
|
||||
}
|
||||
|
||||
/// Process a single message and get the response
|
||||
@@ -728,7 +733,10 @@ impl CliSession {
|
||||
println!("{}", console::style("Generating Recipe").green());
|
||||
|
||||
output::show_thinking();
|
||||
let recipe = self.agent.create_recipe(self.messages.clone()).await;
|
||||
let recipe = self
|
||||
.agent
|
||||
.create_recipe(&self.session_id, self.messages.clone())
|
||||
.await;
|
||||
output::hide_thinking();
|
||||
|
||||
match recipe {
|
||||
@@ -782,16 +790,24 @@ impl CliSession {
|
||||
plan_messages: Conversation,
|
||||
reasoner: Arc<dyn Provider>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let plan_prompt = self.agent.get_plan_prompt().await?;
|
||||
let plan_prompt = self.agent.get_plan_prompt(&self.session_id).await?;
|
||||
output::show_thinking();
|
||||
let (plan_response, _usage) = reasoner
|
||||
.complete(&plan_prompt, plan_messages.messages(), &[])
|
||||
.complete(
|
||||
&self.session_id,
|
||||
&plan_prompt,
|
||||
plan_messages.messages(),
|
||||
&[],
|
||||
)
|
||||
.await?;
|
||||
output::render_message(&plan_response, self.debug);
|
||||
output::hide_thinking();
|
||||
let planner_response_type =
|
||||
classify_planner_response(plan_response.as_concat_text(), self.agent.provider().await?)
|
||||
.await?;
|
||||
let planner_response_type = classify_planner_response(
|
||||
&self.session_id,
|
||||
plan_response.as_concat_text(),
|
||||
self.agent.provider().await?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
match planner_response_type {
|
||||
PlannerResponseType::Plan => {
|
||||
@@ -1154,7 +1170,7 @@ impl CliSession {
|
||||
/// This should be called before the interactive session starts
|
||||
pub async fn update_completion_cache(&mut self) -> Result<()> {
|
||||
// Get fresh data
|
||||
let prompts = self.agent.list_extension_prompts().await;
|
||||
let prompts = self.agent.list_extension_prompts(&self.session_id).await;
|
||||
|
||||
// Update the cache with write lock
|
||||
let mut cache = self.completion_cache.write().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user