mirror of
https://github.com/block/goose.git
synced 2026-10-19 09:34:12 +00:00
This commit is contained in:
parent
e110fbab96
commit
ec52906b67
20 changed files with 100 additions and 134 deletions
|
|
@ -335,21 +335,16 @@ impl<'a, S: MaybeSync, E: InferenceEffect> InferenceRunner<'a, S, E> {
|
|||
effects
|
||||
}
|
||||
|
||||
async fn emit_message(&self, message: Message, emit: &Emitter) {
|
||||
fn emit_message(&self, message: Message, emit: &Emitter) {
|
||||
let message = message.with_generated_id_if_missing();
|
||||
self.output().accumulator.push(message.clone());
|
||||
emit.message(message).await;
|
||||
emit.message(message);
|
||||
}
|
||||
|
||||
async fn error_outcome(
|
||||
&self,
|
||||
err: &ProviderError,
|
||||
emit: &Emitter,
|
||||
) -> Result<OperationResult<E>> {
|
||||
fn error_outcome(&self, err: &ProviderError, emit: &Emitter) -> Result<OperationResult<E>> {
|
||||
tracing::Span::current().record("error.type", err.telemetry_type());
|
||||
tracing::error!("LLM provider error: {err}");
|
||||
self.emit_message(Message::from_provider_error(err), emit)
|
||||
.await;
|
||||
self.emit_message(Message::from_provider_error(err), emit);
|
||||
applied(self.take_output())
|
||||
}
|
||||
}
|
||||
|
|
@ -453,7 +448,7 @@ impl<S: MaybeSync, E: InferenceEffect> Inference<S, E> for InferenceRunner<'_, S
|
|||
|
||||
let mut stream = match stream {
|
||||
Ok(stream) => stream,
|
||||
Err(err) => return self.error_outcome(&err, emit).await,
|
||||
Err(err) => return self.error_outcome(&err, emit),
|
||||
};
|
||||
|
||||
let requested_model = self.model_config.model_name.clone();
|
||||
|
|
@ -475,7 +470,7 @@ impl<S: MaybeSync, E: InferenceEffect> Inference<S, E> for InferenceRunner<'_, S
|
|||
while let Some(result) = stream.next().await {
|
||||
let (msg_opt, usage_opt) = match result {
|
||||
Ok(chunk) => chunk,
|
||||
Err(err) => return self.error_outcome(&err, emit).await,
|
||||
Err(err) => return self.error_outcome(&err, emit),
|
||||
};
|
||||
if let Some(usage) = usage_opt {
|
||||
record_chat_usage(&tracing::Span::current(), &usage);
|
||||
|
|
@ -497,7 +492,7 @@ impl<S: MaybeSync, E: InferenceEffect> Inference<S, E> for InferenceRunner<'_, S
|
|||
if chunk.content.is_empty() && !chunk.metadata.output_token_limit_reached {
|
||||
self.output().accumulator.push(chunk);
|
||||
} else {
|
||||
self.emit_message(chunk, emit).await;
|
||||
self.emit_message(chunk, emit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -547,7 +542,7 @@ impl<S: MaybeSync, E: InferenceEffect> Inference<S, E> for InferenceRunner<'_, S
|
|||
output.accumulator.clear();
|
||||
message
|
||||
};
|
||||
self.emit_message(message, emit).await;
|
||||
self.emit_message(message, emit);
|
||||
}
|
||||
applied(self.take_output())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ where
|
|||
.and_then(|conversation| messages_since_kickoff(conversation).ok())
|
||||
.and_then(interrupted_response);
|
||||
if let Some(response) = unanswered {
|
||||
let effects = vec![E::from(emit.message(response).await)];
|
||||
let effects = vec![E::from(emit.message(response))];
|
||||
session = self
|
||||
.save(runtime, session_id, session, effects, emit)
|
||||
.await?;
|
||||
|
|
|
|||
|
|
@ -260,13 +260,13 @@ impl Emitter {
|
|||
Self { tx, cancel }
|
||||
}
|
||||
|
||||
pub async fn emit(&self, event: AgentEvent) {
|
||||
pub fn emit(&self, event: AgentEvent) {
|
||||
let _ = self.tx.send(event);
|
||||
}
|
||||
|
||||
pub async fn message(&self, message: Message) -> Message {
|
||||
pub fn message(&self, message: Message) -> Message {
|
||||
let message = message.with_generated_id_if_missing();
|
||||
self.emit(AgentEvent::Message(message.clone())).await;
|
||||
self.emit(AgentEvent::Message(message.clone()));
|
||||
message
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ where
|
|||
) -> Vec<E> {
|
||||
let response = self.response.lock().unwrap().take();
|
||||
match response {
|
||||
Some(response) => vec![E::from(emit.message(response).await)],
|
||||
Some(response) => vec![E::from(emit.message(response))],
|
||||
None => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
|
@ -391,7 +391,7 @@ where
|
|||
.unwrap()
|
||||
.take()
|
||||
.expect("tool responses retained");
|
||||
let message = emit.message(message).await;
|
||||
let message = emit.message(message);
|
||||
applied([E::from(message)])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ impl Operation<Session, GooseEffect> for BangShellOperation {
|
|||
);
|
||||
let request = Message::assistant()
|
||||
.with_tool_request(format!("bang_shell_{}", uuid::Uuid::now_v7()), Ok(call));
|
||||
let request = emit.message(request).await;
|
||||
let request = emit.message(request);
|
||||
|
||||
applied([request.into()])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ impl CompactionOperation {
|
|||
}
|
||||
}
|
||||
|
||||
async fn command_error(
|
||||
fn command_error(
|
||||
conversation: &Conversation,
|
||||
message: String,
|
||||
emit: &Emitter,
|
||||
|
|
@ -115,8 +115,8 @@ impl CompactionOperation {
|
|||
let response = Message::assistant()
|
||||
.with_text(message)
|
||||
.with_visibility(true, false);
|
||||
emit.message(command).await;
|
||||
let response = emit.message(response).await;
|
||||
emit.message(command);
|
||||
let response = emit.message(response);
|
||||
yielded_with([
|
||||
ConversationEffect::SetMessageVisibility {
|
||||
message_id,
|
||||
|
|
@ -128,10 +128,7 @@ impl CompactionOperation {
|
|||
])
|
||||
}
|
||||
|
||||
async fn clear(
|
||||
conversation: &Conversation,
|
||||
emit: &Emitter,
|
||||
) -> Result<OperationResult<GooseEffect>> {
|
||||
fn clear(conversation: &Conversation, emit: &Emitter) -> Result<OperationResult<GooseEffect>> {
|
||||
let command = messages_since_kickoff(conversation)?
|
||||
.first()
|
||||
.cloned()
|
||||
|
|
@ -140,8 +137,8 @@ impl CompactionOperation {
|
|||
let response = Message::assistant()
|
||||
.with_text("Conversation cleared")
|
||||
.with_visibility(true, false);
|
||||
let command = emit.message(command).await;
|
||||
let response = emit.message(response).await;
|
||||
let command = emit.message(command);
|
||||
let response = emit.message(response);
|
||||
yielded_with([
|
||||
Conversation::default().into(),
|
||||
command.into(),
|
||||
|
|
@ -164,7 +161,7 @@ impl Operation<Session, GooseEffect> for CompactionOperation {
|
|||
emit: &Emitter,
|
||||
) -> Result<OperationResult<GooseEffect>> {
|
||||
match command.command {
|
||||
"clear" => return Self::clear(conversation, emit).await,
|
||||
"clear" => return Self::clear(conversation, emit),
|
||||
"compact" => {}
|
||||
_ => return not_applicable(),
|
||||
}
|
||||
|
|
@ -188,7 +185,7 @@ impl Operation<Session, GooseEffect> for CompactionOperation {
|
|||
Ok(result) => result,
|
||||
Err(error) => {
|
||||
span.record("error.type", "compaction_error");
|
||||
return Self::command_error(conversation, error.to_string(), emit).await;
|
||||
return Self::command_error(conversation, error.to_string(), emit);
|
||||
}
|
||||
};
|
||||
let compacted = result.conversation;
|
||||
|
|
@ -203,8 +200,8 @@ impl Operation<Session, GooseEffect> for CompactionOperation {
|
|||
let response = Message::assistant()
|
||||
.with_text("Compaction complete")
|
||||
.with_visibility(true, false);
|
||||
emit.message(command).await;
|
||||
let response = emit.message(response).await;
|
||||
emit.message(command);
|
||||
let response = emit.message(response);
|
||||
yielded_with([
|
||||
GooseEffect::CompactConversation {
|
||||
conversation: compacted,
|
||||
|
|
@ -296,13 +293,11 @@ impl Operation<Session, GooseEffect> for CompactionOperation {
|
|||
"Exceeded auto-compact threshold of {threshold_percentage}%. \
|
||||
Performing auto-compaction..."
|
||||
),
|
||||
))
|
||||
.await;
|
||||
));
|
||||
emit.message(Message::assistant().with_system_notification(
|
||||
SystemNotificationType::ThinkingMessage,
|
||||
COMPACTION_THINKING_TEXT,
|
||||
))
|
||||
.await;
|
||||
));
|
||||
|
||||
let span = chat_span(
|
||||
self.provider.as_ref(),
|
||||
|
|
@ -327,8 +322,7 @@ impl Operation<Session, GooseEffect> for CompactionOperation {
|
|||
emit.message(Message::assistant().with_system_notification(
|
||||
SystemNotificationType::InlineMessage,
|
||||
"Compaction complete",
|
||||
))
|
||||
.await;
|
||||
));
|
||||
applied([GooseEffect::CompactConversation {
|
||||
conversation: compacted,
|
||||
usage: Some(usage),
|
||||
|
|
@ -339,8 +333,7 @@ impl Operation<Session, GooseEffect> for CompactionOperation {
|
|||
emit.message(Message::assistant().with_text(format!(
|
||||
"Ran into this error trying to compact: {e}.\n\n\
|
||||
Please try again or create a new session"
|
||||
)))
|
||||
.await;
|
||||
)));
|
||||
yielded()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ impl Operation<Session, GooseEffect> for DoctorOperation {
|
|||
if result.role == Role::Assistant {
|
||||
let command_message = command_message.with_visibility(true, false);
|
||||
let result = result.with_visibility(true, false);
|
||||
emit.message(command_message).await;
|
||||
let result = emit.message(result).await;
|
||||
emit.message(command_message);
|
||||
let result = emit.message(result);
|
||||
return yielded_with([
|
||||
ConversationEffect::SetMessageVisibility {
|
||||
message_id,
|
||||
|
|
|
|||
|
|
@ -44,8 +44,7 @@ impl Operation<Session, GooseEffect> for EmptyResponseOperation {
|
|||
.id
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("Persisted empty-response fallback has no id"))?;
|
||||
emit.message(fallback.clone().with_visibility(true, true))
|
||||
.await;
|
||||
emit.message(fallback.clone().with_visibility(true, true));
|
||||
applied([ConversationEffect::SetMessageVisibility {
|
||||
message_id,
|
||||
user_visible: true,
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ fn readable_output(output: &str) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
async fn subagent_result_message(
|
||||
fn subagent_result_message(
|
||||
subagent_id: &str,
|
||||
outcome: SubagentOutcome,
|
||||
others_waiting: bool,
|
||||
|
|
@ -123,7 +123,7 @@ async fn subagent_result_message(
|
|||
),
|
||||
SubagentOutcome::Cancelled => return None,
|
||||
};
|
||||
emit.message(inline_notice(notice)).await;
|
||||
emit.message(inline_notice(notice));
|
||||
let mut message = Message::user().with_text(text).with_visibility(false, true);
|
||||
message
|
||||
.metadata
|
||||
|
|
@ -207,8 +207,7 @@ impl Operation<Session, GooseEffect> for ForegroundSubagentOperation {
|
|||
let Some(subagent_id) = stopped.subagent_ids.remove(&task_id) else {
|
||||
continue;
|
||||
};
|
||||
if let Some(message) = subagent_result_message(&subagent_id, outcome, true, emit).await
|
||||
{
|
||||
if let Some(message) = subagent_result_message(&subagent_id, outcome, true, emit) {
|
||||
effects.push(message);
|
||||
delivered.insert(subagent_id);
|
||||
}
|
||||
|
|
@ -252,14 +251,13 @@ impl Operation<Session, GooseEffect> for ForegroundSubagentOperation {
|
|||
{
|
||||
SubagentStart::HasOutcome(outcome) => {
|
||||
if let Some(message) =
|
||||
subagent_result_message(subagent_id, outcome, pending.len() > 1, emit).await
|
||||
subagent_result_message(subagent_id, outcome, pending.len() > 1, emit)
|
||||
{
|
||||
return applied([message]);
|
||||
}
|
||||
}
|
||||
SubagentStart::Started { task, run } => {
|
||||
emit.message(inline_notice(start_notice(subagent_id, task.as_deref())))
|
||||
.await;
|
||||
emit.message(inline_notice(start_notice(subagent_id, task.as_deref())));
|
||||
let handle = running.tasks.spawn(run.in_current_span());
|
||||
running
|
||||
.subagent_ids
|
||||
|
|
@ -281,7 +279,7 @@ impl Operation<Session, GooseEffect> for ForegroundSubagentOperation {
|
|||
.subagent_ids
|
||||
.remove(&task_id)
|
||||
.ok_or_else(|| anyhow!("Unknown foreground subagent task {task_id}"))?;
|
||||
match subagent_result_message(&subagent_id, outcome, pending.len() > 1, emit).await {
|
||||
match subagent_result_message(&subagent_id, outcome, pending.len() > 1, emit) {
|
||||
Some(message) => applied([message]),
|
||||
None => not_applicable(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ impl Operation<Session, GooseEffect> for MaxTurnsOperation {
|
|||
}
|
||||
|
||||
let message = Message::assistant().with_text(MAX_TURNS_MESSAGE);
|
||||
let message = emit.message(message).await;
|
||||
let message = emit.message(message);
|
||||
yielded_with([message.into()])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ impl RecipeOperation {
|
|||
self.response.lock().unwrap().take()
|
||||
}
|
||||
|
||||
async fn command_error(
|
||||
fn command_error(
|
||||
&self,
|
||||
conversation: &Conversation,
|
||||
message: String,
|
||||
|
|
@ -85,8 +85,8 @@ impl RecipeOperation {
|
|||
let response = Message::assistant()
|
||||
.with_text(message)
|
||||
.with_visibility(true, false);
|
||||
emit.message(command).await;
|
||||
let response = emit.message(response).await;
|
||||
emit.message(command);
|
||||
let response = emit.message(response);
|
||||
yielded_with([
|
||||
ConversationEffect::SetMessageVisibility {
|
||||
message_id,
|
||||
|
|
@ -112,7 +112,7 @@ impl Operation<Session, GooseEffect> for RecipeOperation {
|
|||
emit: &Emitter,
|
||||
) -> Vec<GooseEffect> {
|
||||
match self.take_response() {
|
||||
Some(response) => vec![emit.message(response).await.into()],
|
||||
Some(response) => vec![emit.message(response).into()],
|
||||
None => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
|
@ -130,14 +130,16 @@ impl Operation<Session, GooseEffect> for RecipeOperation {
|
|||
) {
|
||||
Ok(Some(recipe)) => recipe,
|
||||
Ok(None) => return not_applicable(),
|
||||
Err(error) => return self.command_error(conversation, error, emit).await,
|
||||
Err(error) => return self.command_error(conversation, error, emit),
|
||||
};
|
||||
|
||||
if let Some(response) = recipe.response.clone() {
|
||||
if let Err(error) = FinalOutputTool::try_new(response) {
|
||||
return self
|
||||
.command_error(conversation, format!("Recipe is not valid: {error}"), emit)
|
||||
.await;
|
||||
return self.command_error(
|
||||
conversation,
|
||||
format!("Recipe is not valid: {error}"),
|
||||
emit,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -193,13 +195,11 @@ impl Operation<Session, GooseEffect> for RecipeOperation {
|
|||
};
|
||||
|
||||
if !self.provider.supports_builtin_tools() {
|
||||
return self
|
||||
.command_error(
|
||||
conversation,
|
||||
structured_output_unsupported_message(self.provider.get_name()),
|
||||
emit,
|
||||
)
|
||||
.await;
|
||||
return self.command_error(
|
||||
conversation,
|
||||
structured_output_unsupported_message(self.provider.get_name()),
|
||||
emit,
|
||||
);
|
||||
}
|
||||
|
||||
let messages = messages_since_kickoff(conversation)?;
|
||||
|
|
@ -222,7 +222,7 @@ impl Operation<Session, GooseEffect> for RecipeOperation {
|
|||
)])),
|
||||
request.metadata.as_ref(),
|
||||
);
|
||||
let response = emit.message(response).await;
|
||||
let response = emit.message(response);
|
||||
return applied([response.into()]);
|
||||
}
|
||||
if FinalOutputTool::has_unanswered_siblings(messages, &request.id) {
|
||||
|
|
@ -297,14 +297,14 @@ impl Operation<Session, GooseEffect> for RecipeOperation {
|
|||
.await;
|
||||
}
|
||||
let response = self.take_response().expect("recipe response held");
|
||||
let response = emit.message(response).await;
|
||||
let response = emit.message(response);
|
||||
return applied([response.into()]);
|
||||
}
|
||||
|
||||
if let Some(output) = FinalOutputTool::successful_output(messages) {
|
||||
if last_effective_role(messages)? == EffectiveRole::Tool {
|
||||
let message = Message::assistant().with_text(output);
|
||||
let message = emit.message(message).await;
|
||||
let message = emit.message(message);
|
||||
return applied([message.into()]);
|
||||
}
|
||||
return not_applicable();
|
||||
|
|
@ -314,7 +314,7 @@ impl Operation<Session, GooseEffect> for RecipeOperation {
|
|||
let message = Message::user()
|
||||
.with_text(FINAL_OUTPUT_CONTINUATION_MESSAGE)
|
||||
.agent_only();
|
||||
let message = emit.message(message).await;
|
||||
let message = emit.message(message);
|
||||
return applied([message.into()]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -139,8 +139,8 @@ impl Operation<Session, GooseEffect> for RetryOperation {
|
|||
.ok_or_else(|| anyhow!("Persisted slash command message has no id"))?;
|
||||
let command_message = command_message.with_visibility(true, false);
|
||||
let response = response.with_visibility(true, false);
|
||||
emit.message(command_message).await;
|
||||
let response = emit.message(response).await;
|
||||
emit.message(command_message);
|
||||
let response = emit.message(response);
|
||||
|
||||
let mut effects = vec![
|
||||
ConversationEffect::SetMessageVisibility {
|
||||
|
|
@ -195,8 +195,7 @@ impl Operation<Session, GooseEffect> for RetryOperation {
|
|||
emit.message(Message::assistant().with_system_notification(
|
||||
SystemNotificationType::InlineMessage,
|
||||
format!("Goal: {goal}"),
|
||||
))
|
||||
.await;
|
||||
));
|
||||
return applied([message.into()]);
|
||||
}
|
||||
}
|
||||
|
|
@ -213,8 +212,7 @@ impl Operation<Session, GooseEffect> for RetryOperation {
|
|||
emit.message(Message::assistant().with_system_notification(
|
||||
SystemNotificationType::InlineMessage,
|
||||
format!("Grind: {grind}"),
|
||||
))
|
||||
.await;
|
||||
));
|
||||
return applied([message.into()]);
|
||||
}
|
||||
|
||||
|
|
@ -235,7 +233,7 @@ impl Operation<Session, GooseEffect> for RetryOperation {
|
|||
let success = match success {
|
||||
Ok(success) => success,
|
||||
Err(error) => {
|
||||
let message = emit.message(retry_error(&error.to_string())).await;
|
||||
let message = emit.message(retry_error(&error.to_string()));
|
||||
return applied([message.into()]);
|
||||
}
|
||||
};
|
||||
|
|
@ -257,7 +255,7 @@ impl Operation<Session, GooseEffect> for RetryOperation {
|
|||
"retry_max_exceeded",
|
||||
&format!("Max retries ({}) exceeded", retry_config.max_retries),
|
||||
);
|
||||
let message = emit.message(message).await;
|
||||
let message = emit.message(message);
|
||||
return applied([message.into()]);
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +265,7 @@ impl Operation<Session, GooseEffect> for RetryOperation {
|
|||
.map(Duration::from_secs)
|
||||
.unwrap_or(self.on_failure_timeout);
|
||||
if let Err(error) = execute_on_failure_command_with_timeout(command, timeout).await {
|
||||
let message = emit.message(retry_error(&error.to_string())).await;
|
||||
let message = emit.message(retry_error(&error.to_string()));
|
||||
return applied([message.into()]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ impl SkillOperation {
|
|||
Some(session)
|
||||
}
|
||||
|
||||
async fn command_response(
|
||||
fn command_response(
|
||||
conversation: &Conversation,
|
||||
message: String,
|
||||
emit: &Emitter,
|
||||
|
|
@ -236,8 +236,8 @@ impl SkillOperation {
|
|||
let response = Message::assistant()
|
||||
.with_text(message)
|
||||
.with_visibility(true, false);
|
||||
emit.message(command).await;
|
||||
let response = emit.message(response).await;
|
||||
emit.message(command);
|
||||
let response = emit.message(response);
|
||||
yielded_with([
|
||||
ConversationEffect::SetMessageVisibility {
|
||||
message_id,
|
||||
|
|
@ -270,8 +270,7 @@ impl Operation<Session, GooseEffect> for SkillOperation {
|
|||
&session.working_dir,
|
||||
)),
|
||||
emit,
|
||||
)
|
||||
.await;
|
||||
);
|
||||
}
|
||||
|
||||
let prompt = match crate::slash_commands::skill_slash_command::resolve_command(
|
||||
|
|
@ -281,7 +280,7 @@ impl Operation<Session, GooseEffect> for SkillOperation {
|
|||
) {
|
||||
Ok(Some(prompt)) => prompt,
|
||||
Ok(None) => return not_applicable(),
|
||||
Err(error) => return Self::command_response(conversation, error, emit).await,
|
||||
Err(error) => return Self::command_response(conversation, error, emit),
|
||||
};
|
||||
let command_message = messages_since_kickoff(conversation)?
|
||||
.first()
|
||||
|
|
@ -426,7 +425,7 @@ impl Operation<Session, GooseEffect> for SkillOperation {
|
|||
};
|
||||
response.add_tool_response_with_metadata(request.id, result, request.metadata.as_ref());
|
||||
}
|
||||
let response = emit.message(response).await;
|
||||
let response = emit.message(response);
|
||||
applied([response.into()])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,9 +69,8 @@ impl Operation<Session, GooseEffect> for StatusOperation {
|
|||
.id
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("Persisted slash command message has no id"))?;
|
||||
emit.message(command_message.with_visibility(true, false))
|
||||
.await;
|
||||
let response = emit.message(response).await;
|
||||
emit.message(command_message.with_visibility(true, false));
|
||||
let response = emit.message(response);
|
||||
yielded_with([
|
||||
ConversationEffect::SetMessageVisibility {
|
||||
message_id,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ impl Operation<Session, GooseEffect> for SteerOperation {
|
|||
|
||||
let mut drained = Vec::with_capacity(pending.len());
|
||||
for message in pending {
|
||||
drained.push(emit.message(message).await);
|
||||
drained.push(emit.message(message));
|
||||
}
|
||||
*self.drained.lock().unwrap() = drained.clone();
|
||||
for message in drained {
|
||||
|
|
|
|||
|
|
@ -106,12 +106,12 @@ impl Operation<Session, GooseEffect> for StopHookOperation {
|
|||
+ 1;
|
||||
if blocks > self.block_cap {
|
||||
let warning = block_cap_warning(&plugin, self.block_cap);
|
||||
let warning = emit.message(warning).await;
|
||||
let warning = emit.message(warning);
|
||||
yielded_with([warning.into()])
|
||||
} else {
|
||||
let mut denial = denial_context_message(&plugin, &reason);
|
||||
self.set_message_meta(&mut denial, DENIED, serde_json::json!(true));
|
||||
emit.message(denial_notification(&plugin)).await;
|
||||
emit.message(denial_notification(&plugin));
|
||||
applied([denial.into()])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -475,7 +475,7 @@ impl ToolExecutionOperation {
|
|||
.await
|
||||
}
|
||||
|
||||
async fn command_response(
|
||||
fn command_response(
|
||||
conversation: &Conversation,
|
||||
message: String,
|
||||
emit: &Emitter,
|
||||
|
|
@ -492,8 +492,8 @@ impl ToolExecutionOperation {
|
|||
let response = Message::assistant()
|
||||
.with_text(message)
|
||||
.with_visibility(true, false);
|
||||
emit.message(command).await;
|
||||
let response = emit.message(response).await;
|
||||
emit.message(command);
|
||||
let response = emit.message(response);
|
||||
yielded_with([
|
||||
ConversationEffect::SetMessageVisibility {
|
||||
message_id,
|
||||
|
|
@ -524,8 +524,7 @@ impl ToolExecutionOperation {
|
|||
conversation,
|
||||
format!("Extension '{filter}' not found"),
|
||||
emit,
|
||||
)
|
||||
.await;
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -546,7 +545,7 @@ impl ToolExecutionOperation {
|
|||
output.push('\n');
|
||||
}
|
||||
}
|
||||
Self::command_response(conversation, output, emit).await
|
||||
Self::command_response(conversation, output, emit)
|
||||
}
|
||||
|
||||
async fn run_prompt(
|
||||
|
|
@ -562,8 +561,7 @@ impl ToolExecutionOperation {
|
|||
conversation,
|
||||
"Prompt name argument is required".to_string(),
|
||||
emit,
|
||||
)
|
||||
.await;
|
||||
);
|
||||
};
|
||||
let prompts = self
|
||||
.lease(session)
|
||||
|
|
@ -581,8 +579,7 @@ impl ToolExecutionOperation {
|
|||
conversation,
|
||||
format!("Prompt '{prompt_name}' not found"),
|
||||
emit,
|
||||
)
|
||||
.await;
|
||||
);
|
||||
};
|
||||
|
||||
if params.get(1) == Some(&"--info") {
|
||||
|
|
@ -601,7 +598,7 @@ impl ToolExecutionOperation {
|
|||
output.push('\n');
|
||||
}
|
||||
}
|
||||
return Self::command_response(conversation, output, emit).await;
|
||||
return Self::command_response(conversation, output, emit);
|
||||
}
|
||||
|
||||
let arguments: HashMap<_, _> = params
|
||||
|
|
@ -623,7 +620,7 @@ impl ToolExecutionOperation {
|
|||
{
|
||||
Ok(result) => result,
|
||||
Err(error) => {
|
||||
return Self::command_response(conversation, error.to_string(), emit).await;
|
||||
return Self::command_response(conversation, error.to_string(), emit);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -655,8 +652,7 @@ impl ToolExecutionOperation {
|
|||
message.role
|
||||
),
|
||||
emit,
|
||||
)
|
||||
.await;
|
||||
);
|
||||
}
|
||||
effects.push(message.with_visibility(false, true).into());
|
||||
}
|
||||
|
|
@ -665,8 +661,7 @@ impl ToolExecutionOperation {
|
|||
conversation,
|
||||
format!("Prompt '{prompt_name}' returned no messages"),
|
||||
emit,
|
||||
)
|
||||
.await;
|
||||
);
|
||||
}
|
||||
applied(effects)
|
||||
}
|
||||
|
|
@ -823,8 +818,7 @@ impl Operation<Session, GooseEffect> for ToolExecutionOperation {
|
|||
) -> Vec<GooseEffect> {
|
||||
let (actions, response) = self.take_batch();
|
||||
if let Some(response) = &response {
|
||||
emit.emit(AgentEvent::Message(response.user_visible_content()))
|
||||
.await;
|
||||
emit.emit(AgentEvent::Message(response.user_visible_content()));
|
||||
}
|
||||
actions
|
||||
.into_iter()
|
||||
|
|
@ -975,7 +969,7 @@ impl Operation<Session, GooseEffect> for ToolExecutionOperation {
|
|||
request.metadata.as_ref(),
|
||||
);
|
||||
}
|
||||
let response = emit.message(response).await;
|
||||
let response = emit.message(response);
|
||||
return applied([response.into()]);
|
||||
};
|
||||
|
||||
|
|
@ -1015,7 +1009,7 @@ impl Operation<Session, GooseEffect> for ToolExecutionOperation {
|
|||
request.metadata.as_ref(),
|
||||
);
|
||||
}
|
||||
let response = emit.message(response).await;
|
||||
let response = emit.message(response);
|
||||
return applied([response.into()]);
|
||||
}
|
||||
|
||||
|
|
@ -1088,8 +1082,7 @@ impl Operation<Session, GooseEffect> for ToolExecutionOperation {
|
|||
emit.emit(AgentEvent::McpNotification((
|
||||
request_id.clone(),
|
||||
notification,
|
||||
)))
|
||||
.await;
|
||||
)));
|
||||
}
|
||||
}
|
||||
let metadata = requests
|
||||
|
|
@ -1102,21 +1095,19 @@ impl Operation<Session, GooseEffect> for ToolExecutionOperation {
|
|||
.record(&request_id, output, metadata);
|
||||
}
|
||||
ToolStreamItem::Message(msg) => {
|
||||
emit.emit(AgentEvent::McpNotification((request_id, msg)))
|
||||
.await;
|
||||
emit.emit(AgentEvent::McpNotification((request_id, msg)));
|
||||
}
|
||||
ToolStreamItem::ActionRequired(msg) => {
|
||||
let msg = msg.with_generated_id_if_missing();
|
||||
self.batch.lock().unwrap().actions.push(msg.clone());
|
||||
emit.message(msg).await;
|
||||
emit.message(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (actions, response) = self.take_batch();
|
||||
let response = response.ok_or_else(|| anyhow!("tool batch produced no responses"))?;
|
||||
emit.emit(AgentEvent::Message(response.user_visible_content()))
|
||||
.await;
|
||||
emit.emit(AgentEvent::Message(response.user_visible_content()));
|
||||
applied(actions.into_iter().chain([response]).map(GooseEffect::from))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ impl Operation<Session, GooseEffect> for UnknownToolOperation {
|
|||
response.add_tool_response_with_metadata(request.id, result, metadata.as_ref());
|
||||
}
|
||||
|
||||
let response = emit.message(response).await;
|
||||
let response = emit.message(response);
|
||||
applied([response.into()])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ impl EffectHandler<Session, GooseEffect> for SessionManager {
|
|||
GooseEffect::Conversation(ConversationEffect::AppendMessage(message)) => {
|
||||
if contains_tool_confirmation_request(message) {
|
||||
// Responses can arrive immediately, so publish only after the persistence pass.
|
||||
emit.emit(AgentEvent::Message(message.clone())).await;
|
||||
emit.emit(AgentEvent::Message(message.clone()));
|
||||
}
|
||||
if let Some(usage) = message
|
||||
.metadata
|
||||
|
|
@ -133,8 +133,7 @@ impl EffectHandler<Session, GooseEffect> for SessionManager {
|
|||
emit.emit(AgentEvent::MessageUsage {
|
||||
message_id: message.id.clone(),
|
||||
usage,
|
||||
})
|
||||
.await;
|
||||
});
|
||||
}
|
||||
}
|
||||
GooseEffect::Conversation(ConversationEffect::ReplaceConversation(
|
||||
|
|
@ -144,12 +143,9 @@ impl EffectHandler<Session, GooseEffect> for SessionManager {
|
|||
emit.emit(AgentEvent::HistoryReplaced(replaced_history(
|
||||
conversation,
|
||||
&effects[index + 1..],
|
||||
)))
|
||||
.await;
|
||||
}
|
||||
GooseEffect::RecordUsage(usage) => {
|
||||
emit.emit(AgentEvent::Usage(usage.clone())).await
|
||||
)));
|
||||
}
|
||||
GooseEffect::RecordUsage(usage) => emit.emit(AgentEvent::Usage(usage.clone())),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,9 +68,7 @@ impl Inference<Session, GooseEffect> for TestInference {
|
|||
.find(|message| message.role == rmcp::model::Role::User)
|
||||
.map(Message::as_concat_text)
|
||||
.unwrap();
|
||||
let message = emit
|
||||
.message(Message::assistant().with_text(format!("{prompt} answered")))
|
||||
.await;
|
||||
let message = emit.message(Message::assistant().with_text(format!("{prompt} answered")));
|
||||
yielded_with([
|
||||
GooseEffect::from(message),
|
||||
GooseEffect::RecordUsage(ProviderUsage::new(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue