Jazzcort add timeout (#6772)
Signed-off-by: Jazzcort <jason101011113@gmail.com> Co-authored-by: Jazzcort <jason101011113@gmail.com> Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
@@ -112,6 +112,38 @@ pub struct SessionOptions {
|
|||||||
pub container: Option<String>,
|
pub container: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct StreamableHttpOptions {
|
||||||
|
pub url: String,
|
||||||
|
pub timeout: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_streamable_http_extension(input: &str) -> Result<StreamableHttpOptions, String> {
|
||||||
|
let mut input_iter = input.split_whitespace();
|
||||||
|
let (mut url, mut timeout) = (String::new(), goose::config::DEFAULT_EXTENSION_TIMEOUT);
|
||||||
|
|
||||||
|
if let Some(url_str) = input_iter.next() {
|
||||||
|
url.push_str(url_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
for kv_pair in input_iter {
|
||||||
|
if !kv_pair.contains('=') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (key, value) = kv_pair.split_once('=').unwrap();
|
||||||
|
|
||||||
|
// We Can have more keys here for setting other properties
|
||||||
|
if key == "timeout" {
|
||||||
|
if let Ok(seconds) = value.parse::<u64>() {
|
||||||
|
timeout = seconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(StreamableHttpOptions { url, timeout })
|
||||||
|
}
|
||||||
|
|
||||||
/// Extension configuration options shared between Session and Run commands
|
/// Extension configuration options shared between Session and Run commands
|
||||||
#[derive(Args, Debug, Clone, Default)]
|
#[derive(Args, Debug, Clone, Default)]
|
||||||
pub struct ExtensionOptions {
|
pub struct ExtensionOptions {
|
||||||
@@ -128,10 +160,11 @@ pub struct ExtensionOptions {
|
|||||||
long = "with-streamable-http-extension",
|
long = "with-streamable-http-extension",
|
||||||
value_name = "URL",
|
value_name = "URL",
|
||||||
help = "Add streamable HTTP extensions (can be specified multiple times)",
|
help = "Add streamable HTTP extensions (can be specified multiple times)",
|
||||||
long_help = "Add streamable HTTP extensions from a URL. Can be specified multiple times. Format: 'url...'",
|
long_help = "Add streamable HTTP extensions from a URL. Can be specified multiple times. Format: 'url...' or 'url... timeout=100' to set up timeout other than default",
|
||||||
action = clap::ArgAction::Append
|
action = clap::ArgAction::Append,
|
||||||
|
value_parser = parse_streamable_http_extension
|
||||||
)]
|
)]
|
||||||
pub streamable_http_extensions: Vec<String>,
|
pub streamable_http_extensions: Vec<StreamableHttpOptions>,
|
||||||
|
|
||||||
#[arg(
|
#[arg(
|
||||||
long = "with-builtin",
|
long = "with-builtin",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::cli::StreamableHttpOptions;
|
||||||
use crate::session::build_session;
|
use crate::session::build_session;
|
||||||
use crate::session::SessionBuilderConfig;
|
use crate::session::SessionBuilderConfig;
|
||||||
use crate::{logging, CliSession};
|
use crate::{logging, CliSession};
|
||||||
@@ -34,13 +35,21 @@ pub async fn agent_generator(
|
|||||||
requirements: ExtensionRequirements,
|
requirements: ExtensionRequirements,
|
||||||
session_id: String,
|
session_id: String,
|
||||||
) -> BenchAgent {
|
) -> BenchAgent {
|
||||||
|
let streamable_http_extensions: Vec<StreamableHttpOptions> = requirements
|
||||||
|
.streamable_http
|
||||||
|
.iter()
|
||||||
|
.map(|s| StreamableHttpOptions {
|
||||||
|
url: s.clone(),
|
||||||
|
timeout: goose::config::DEFAULT_EXTENSION_TIMEOUT,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
let base_session = build_session(SessionBuilderConfig {
|
let base_session = build_session(SessionBuilderConfig {
|
||||||
session_id: Some(session_id),
|
session_id: Some(session_id),
|
||||||
resume: false,
|
resume: false,
|
||||||
fork: false,
|
fork: false,
|
||||||
no_session: false,
|
no_session: false,
|
||||||
extensions: requirements.external,
|
extensions: requirements.external,
|
||||||
streamable_http_extensions: requirements.streamable_http,
|
streamable_http_extensions,
|
||||||
builtins: requirements.builtin,
|
builtins: requirements.builtin,
|
||||||
recipe: None,
|
recipe: None,
|
||||||
additional_system_prompt: None,
|
additional_system_prompt: None,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use crate::cli::StreamableHttpOptions;
|
||||||
|
|
||||||
use super::output;
|
use super::output;
|
||||||
use super::CliSession;
|
use super::CliSession;
|
||||||
use console::style;
|
use console::style;
|
||||||
@@ -87,7 +89,7 @@ pub struct SessionBuilderConfig {
|
|||||||
/// List of stdio extension commands to add
|
/// List of stdio extension commands to add
|
||||||
pub extensions: Vec<String>,
|
pub extensions: Vec<String>,
|
||||||
/// List of streamable HTTP extension commands to add
|
/// List of streamable HTTP extension commands to add
|
||||||
pub streamable_http_extensions: Vec<String>,
|
pub streamable_http_extensions: Vec<StreamableHttpOptions>,
|
||||||
/// List of builtin extension commands to add
|
/// List of builtin extension commands to add
|
||||||
pub builtins: Vec<String>,
|
pub builtins: Vec<String>,
|
||||||
/// Recipe for the session
|
/// Recipe for the session
|
||||||
@@ -578,6 +580,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|
||||||
if let Err(e) = session
|
if let Err(e) = session
|
||||||
.agent
|
.agent
|
||||||
.persist_extension_state(&session_id.clone())
|
.persist_extension_state(&session_id.clone())
|
||||||
@@ -629,7 +632,10 @@ mod tests {
|
|||||||
fork: false,
|
fork: false,
|
||||||
no_session: false,
|
no_session: false,
|
||||||
extensions: vec!["echo test".to_string()],
|
extensions: vec!["echo test".to_string()],
|
||||||
streamable_http_extensions: vec!["http://localhost:8080/mcp".to_string()],
|
streamable_http_extensions: vec![StreamableHttpOptions {
|
||||||
|
url: "http://localhost:8080/mcp".to_string(),
|
||||||
|
timeout: goose::config::DEFAULT_EXTENSION_TIMEOUT,
|
||||||
|
}],
|
||||||
builtins: vec!["developer".to_string()],
|
builtins: vec!["developer".to_string()],
|
||||||
recipe: None,
|
recipe: None,
|
||||||
additional_system_prompt: Some("Test prompt".to_string()),
|
additional_system_prompt: Some("Test prompt".to_string()),
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ mod prompt;
|
|||||||
mod task_execution_display;
|
mod task_execution_display;
|
||||||
mod thinking;
|
mod thinking;
|
||||||
|
|
||||||
|
use crate::cli::StreamableHttpOptions;
|
||||||
use crate::session::task_execution_display::{
|
use crate::session::task_execution_display::{
|
||||||
format_task_execution_notification, TASK_EXECUTION_NOTIFICATION_TYPE,
|
format_task_execution_notification, TASK_EXECUTION_NOTIFICATION_TYPE,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -418,9 +418,7 @@ export function AppInner() {
|
|||||||
window.electron.reactReady();
|
window.electron.reactReady();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error sending reactReady:', error);
|
console.error('Error sending reactReady:', error);
|
||||||
setFatalError(
|
setFatalError(`React ready notification failed: ${errorMessage(error, 'Unknown error')}`);
|
||||||
`React ready notification failed: ${errorMessage(error, 'Unknown error')}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -90,9 +90,7 @@ export const AlertBox = ({ alert, className }: AlertBoxProps) => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error saving threshold:', error);
|
console.error('Error saving threshold:', error);
|
||||||
window.alert(
|
window.alert(`Failed to save threshold: ${errorMessage(error, 'Unknown error')}`);
|
||||||
`Failed to save threshold: ${errorMessage(error, 'Unknown error')}`
|
|
||||||
);
|
|
||||||
} finally {
|
} finally {
|
||||||
setIsSaving(false);
|
setIsSaving(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,9 +206,7 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose: _onClose }) => {
|
|||||||
setSchedules(fetchedSchedules);
|
setSchedules(fetchedSchedules);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch schedules:', error);
|
console.error('Failed to fetch schedules:', error);
|
||||||
setApiError(
|
setApiError(errorMessage(error, 'An unknown error occurred while fetching schedules.'));
|
||||||
errorMessage(error, 'An unknown error occurred while fetching schedules.')
|
|
||||||
);
|
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -375,8 +373,7 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose: _onClose }) => {
|
|||||||
await fetchSchedules();
|
await fetchSchedules();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to kill running job "${id}":`, error);
|
console.error(`Failed to kill running job "${id}":`, error);
|
||||||
const errorMsg =
|
const errorMsg = errorMessage(error, `Unknown error killing job "${id}".`);
|
||||||
errorMessage(error, `Unknown error killing job "${id}".`);
|
|
||||||
setApiError(errorMsg);
|
setApiError(errorMsg);
|
||||||
toastError({
|
toastError({
|
||||||
title: 'Kill Job Error',
|
title: 'Kill Job Error',
|
||||||
@@ -413,8 +410,7 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose: _onClose }) => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to inspect running job "${id}":`, error);
|
console.error(`Failed to inspect running job "${id}":`, error);
|
||||||
const errorMsg =
|
const errorMsg = errorMessage(error, `Unknown error inspecting job "${id}".`);
|
||||||
errorMessage(error, `Unknown error inspecting job "${id}".`);
|
|
||||||
setApiError(errorMsg);
|
setApiError(errorMsg);
|
||||||
toastError({
|
toastError({
|
||||||
title: 'Inspect Job Error',
|
title: 'Inspect Job Error',
|
||||||
|
|||||||
@@ -189,9 +189,7 @@ const SessionHistoryView: React.FC<SessionHistoryViewProps> = ({
|
|||||||
setIsShareModalOpen(true);
|
setIsShareModalOpen(true);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error sharing session:', error);
|
console.error('Error sharing session:', error);
|
||||||
toast.error(
|
toast.error(`Failed to share session: ${errorMessage(error, 'Unknown error')}`);
|
||||||
`Failed to share session: ${errorMessage(error, 'Unknown error')}`
|
|
||||||
);
|
|
||||||
} finally {
|
} finally {
|
||||||
setIsSharing(false);
|
setIsSharing(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -476,7 +476,9 @@ const SessionListView: React.FC<SessionListViewProps> = React.memo(
|
|||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error deleting session:', error);
|
console.error('Error deleting session:', error);
|
||||||
toast.error(`Failed to delete session "${sessionName}": ${errorMessage(error, 'Unknown error')}`);
|
toast.error(
|
||||||
|
`Failed to delete session "${sessionName}": ${errorMessage(error, 'Unknown error')}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
await loadSessions();
|
await loadSessions();
|
||||||
}, [sessionToDelete, loadSessions]);
|
}, [sessionToDelete, loadSessions]);
|
||||||
|
|||||||
@@ -247,12 +247,7 @@ export function registerUpdateIpcHandlers() {
|
|||||||
log.error('Error downloading update:', error);
|
log.error('Error downloading update:', error);
|
||||||
const version = githubUpdateInfo.latestVersion || lastUpdateState?.latestVersion || 'unknown';
|
const version = githubUpdateInfo.latestVersion || lastUpdateState?.latestVersion || 'unknown';
|
||||||
const method = isUsingGitHubFallback ? 'github-fallback' : 'electron-updater';
|
const method = isUsingGitHubFallback ? 'github-fallback' : 'electron-updater';
|
||||||
trackUpdateDownloadCompleted(
|
trackUpdateDownloadCompleted(false, version, method, errorMessage(error, 'unknown'));
|
||||||
false,
|
|
||||||
version,
|
|
||||||
method,
|
|
||||||
errorMessage(error, 'unknown')
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: errorMessage(error, 'Unknown error'),
|
error: errorMessage(error, 'Unknown error'),
|
||||||
|
|||||||
@@ -58,7 +58,9 @@ export async function loadSession(sessionId: string, forceRefresh = false): Prom
|
|||||||
|
|
||||||
return session;
|
return session;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Error loading session ${sessionId}: ${errorMessage(error, 'Unknown error')}`);
|
throw new Error(
|
||||||
|
`Error loading session ${sessionId}: ${errorMessage(error, 'Unknown error')}`
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
inFlightRequests.delete(sessionId);
|
inFlightRequests.delete(sessionId);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user