Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
15224fb
first wave refactor
katzdave Oct 16, 2025
a795429
rename conversation compacted content
katzdave Oct 16, 2025
814de07
fmt
katzdave Oct 16, 2025
af08051
undo rename
katzdave Oct 16, 2025
69b66f2
rm some comments
katzdave Oct 16, 2025
60aca5e
rm compactioncheckresult
katzdave Oct 16, 2025
d0098b3
rm autocompactresult
katzdave Oct 16, 2025
38f00fe
massive rename fun
katzdave Oct 16, 2025
86d6da7
Merge branch 'main' of github.com:block/goose into dkatz/system-notify
katzdave Oct 16, 2025
97aa4ab
continue renames
katzdave Oct 17, 2025
76252aa
Merge branch 'main' of github.com:block/goose into dkatz/system-notify
katzdave Oct 17, 2025
3689708
massive code delete
katzdave Oct 20, 2025
bcb0b6d
Merge branch 'main' of github.com:block/goose into dkatz/system-notify
katzdave Oct 20, 2025
f9dada8
clean up reply
katzdave Oct 20, 2025
c2139de
force user only on system notifications
katzdave Oct 20, 2025
b0e1dd3
update notificiaiton
katzdave Oct 20, 2025
293a696
client side compact msg
katzdave Oct 20, 2025
85d446e
fix typecheck
katzdave Oct 20, 2025
a3c5278
experimental big thinking msg change
katzdave Oct 20, 2025
8acc16c
simplify slightly
katzdave Oct 20, 2025
46e8c14
Merge branch 'main' of github.com:block/goose into dkatz/system-notify
katzdave Oct 20, 2025
e1c9b62
cli support
katzdave Oct 20, 2025
44f1674
msg string
katzdave Oct 20, 2025
2f623d4
fmt
katzdave Oct 20, 2025
ecb523a
minor cleanup
katzdave Oct 20, 2025
22db6f8
rm a couple more comments
katzdave Oct 20, 2025
9151686
setMessage cleanup in progress
katzdave Oct 20, 2025
4925dba
big change -> client streams compact message
katzdave Oct 20, 2025
dfddf3e
remove messy do_compaction abstraction
katzdave Oct 20, 2025
b82dec7
Change manual compaction command to /compact and remove state setters
katzdave Oct 20, 2025
2cb8636
reply cleanup
katzdave Oct 21, 2025
ab83a4c
minor deletes
katzdave Oct 21, 2025
3c78a6e
Merge branch 'main' of github.com:block/goose into dkatz/system-notify
katzdave Oct 21, 2025
80380bc
clippy and rename
katzdave Oct 21, 2025
b60a69f
delete manual compact routes
katzdave Oct 21, 2025
ea91c6d
Merge branch 'main' of github.com:block/goose into dkatz/system-notify
katzdave Oct 21, 2025
cb1f51c
openapi fix
katzdave Oct 21, 2025
b94efe5
lowercase
katzdave Oct 21, 2025
a8ff2ec
fixes wave 1
katzdave Oct 22, 2025
0841d8c
review pt 2
katzdave Oct 22, 2025
85aeda0
Review pt 2
katzdave Oct 22, 2025
a3130ef
resolved merge conflicts
katzdave Oct 22, 2025
e7c106f
fix clippy diff
katzdave Oct 22, 2025
159d82f
Merge branch 'main' of github.com:block/goose into dkatz/system-notify
katzdave Oct 22, 2025
d1b3f30
Merge main into dkatz/system-notify
katzdave Oct 22, 2025
f32364f
fmt
katzdave Oct 22, 2025
f9c6acb
first pass
katzdave Oct 22, 2025
d31d645
Working e2e
katzdave Oct 23, 2025
1fd21ab
Cleanup
katzdave Oct 23, 2025
57c24d3
Merge branch 'main' of github.com:block/goose into dkatz/token-usage-…
katzdave Oct 23, 2025
8e3cfe5
restore logs
katzdave Oct 23, 2025
b6126ee
token mapping fix
katzdave Oct 24, 2025
6f71766
Clearer token names...
katzdave Oct 24, 2025
0ff3d35
provider always sums to total_tokens
katzdave Oct 24, 2025
250fabe
don't pass usage to message
katzdave Oct 24, 2025
8be519b
lingering usage refs
katzdave Oct 24, 2025
f3aa252
fmt
katzdave Oct 24, 2025
d8af0a0
rename currenTtotalTokens
katzdave Oct 24, 2025
1c2ffcc
cleanup diff
katzdave Oct 24, 2025
e1045fb
merge
katzdave Oct 24, 2025
66bfef0
move to openapi schema
katzdave Oct 24, 2025
560e05b
Merge branch 'main' of github.com:block/goose into dkatz/token-usage-…
katzdave Oct 24, 2025
f05e74f
merge conflicts
katzdave Oct 28, 2025
8dad9e9
rm openapi
katzdave Oct 28, 2025
2e26a6c
regen schema
katzdave Oct 28, 2025
63230e0
merge with schema
katzdave Oct 28, 2025
79c05af
schema gen
katzdave Oct 28, 2025
3f21655
dont use optionsals
katzdave Oct 28, 2025
0dd473d
one more optional ref
katzdave Oct 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions crates/goose-server/src/openapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ use goose::config::declarative_providers::{
};
use goose::conversation::message::{
FrontendToolRequest, Message, MessageContent, MessageMetadata, RedactedThinkingContent,
SystemNotificationContent, SystemNotificationType, ThinkingContent, ToolConfirmationRequest,
ToolRequest, ToolResponse,
SystemNotificationContent, SystemNotificationType, ThinkingContent, TokenState,
ToolConfirmationRequest, ToolRequest, ToolResponse,
};

use crate::routes::reply::MessageEvent;
Expand Down Expand Up @@ -402,6 +402,7 @@ derive_utoipa!(Icon as IconSchema);
Message,
MessageContent,
MessageMetadata,
TokenState,
ContentSchema,
EmbeddedResourceSchema,
ImageContentSchema,
Expand Down
31 changes: 29 additions & 2 deletions crates/goose-server/src/routes/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use axum::{
};
use bytes::Bytes;
use futures::{stream::StreamExt, Stream};
use goose::conversation::message::{Message, MessageContent};
use goose::conversation::message::{Message, MessageContent, TokenState};
use goose::conversation::Conversation;
use goose::permission::{Permission, PermissionConfirmation};
use goose::session::SessionManager;
Expand Down Expand Up @@ -126,6 +126,7 @@ impl IntoResponse for SseResponse {
pub enum MessageEvent {
Message {
message: Message,
token_state: TokenState,
},
Error {
error: String,
Expand Down Expand Up @@ -159,6 +160,7 @@ async fn stream_event(
e
)
});

if tx.send(format!("data: {}\n\n", json)).await.is_err() {
tracing::info!("client hung up");
cancel_token.cancel();
Expand Down Expand Up @@ -305,7 +307,32 @@ pub async fn reply(
}

all_messages.push(message.clone());
stream_event(MessageEvent::Message { message }, &tx, &cancel_token).await;

let token_state = match SessionManager::get_session(&session_id, false).await {
Ok(session) => {
TokenState {
input_tokens: session.input_tokens.unwrap_or(0),
output_tokens: session.output_tokens.unwrap_or(0),
total_tokens: session.total_tokens.unwrap_or(0),
accumulated_input_tokens: session.accumulated_input_tokens.unwrap_or(0),
accumulated_output_tokens: session.accumulated_output_tokens.unwrap_or(0),
accumulated_total_tokens: session.accumulated_total_tokens.unwrap_or(0),
}
},
Err(e) => {
tracing::warn!("Failed to fetch session for token state: {}", e);
TokenState {
input_tokens: 0,
output_tokens: 0,
total_tokens: 0,
accumulated_input_tokens: 0,
accumulated_output_tokens: 0,
accumulated_total_tokens: 0,
}
}
};

stream_event(MessageEvent::Message { message, token_state }, &tx, &cancel_token).await;
}
Ok(Some(Ok(AgentEvent::HistoryReplaced(new_messages)))) => {
all_messages = new_messages.clone();
Expand Down
38 changes: 24 additions & 14 deletions crates/goose/src/agents/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -834,9 +834,11 @@ impl Agent {
}
}
Err(e) => {
yield AgentEvent::Message(Message::assistant().with_text(
format!("Ran into this error trying to compact: {e}.\n\nPlease try again or create a new session")
));
yield AgentEvent::Message(
Message::assistant().with_text(
format!("Ran into this error trying to compact: {e}.\n\nPlease try again or create a new session")
)
);
}
}
}))
Expand Down Expand Up @@ -926,7 +928,7 @@ impl Agent {
if let Some(final_output_tool) = self.final_output_tool.lock().await.as_ref() {
if final_output_tool.final_output.is_some() {
let final_event = AgentEvent::Message(
Message::assistant().with_text(final_output_tool.final_output.clone().unwrap()),
Message::assistant().with_text(final_output_tool.final_output.clone().unwrap())
);
yield final_event;
break;
Expand All @@ -935,9 +937,11 @@ impl Agent {

turns_taken += 1;
if turns_taken > max_turns {
yield AgentEvent::Message(Message::assistant().with_text(
"I've reached the maximum number of actions I can do without user input. Would you like me to continue?"
));
yield AgentEvent::Message(
Message::assistant().with_text(
"I've reached the maximum number of actions I can do without user input. Would you like me to continue?"
)
);
break;
}

Expand Down Expand Up @@ -1187,18 +1191,22 @@ impl Agent {
}
Err(e) => {
error!("Error: {}", e);
yield AgentEvent::Message(Message::assistant().with_text(
yield AgentEvent::Message(
Message::assistant().with_text(
format!("Ran into this error trying to compact: {e}.\n\nPlease retry if you think this is a transient or recoverable error.")
));
)
);
break;
}
}
}
Err(e) => {
error!("Error: {}", e);
yield AgentEvent::Message(Message::assistant().with_text(
yield AgentEvent::Message(
Message::assistant().with_text(
format!("Ran into this error: {e}.\n\nPlease retry if you think this is a transient or recoverable error.")
));
)
);
break;
}
}
Expand Down Expand Up @@ -1233,9 +1241,11 @@ impl Agent {
}
Err(e) => {
error!("Retry logic failed: {}", e);
yield AgentEvent::Message(Message::assistant().with_text(
format!("Retry logic encountered an error: {}", e)
));
yield AgentEvent::Message(
Message::assistant().with_text(
format!("Retry logic encountered an error: {}", e)
)
);
exit_chat = true;
}
}
Expand Down
11 changes: 11 additions & 0 deletions crates/goose/src/conversation/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,17 @@ impl Message {
}
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct TokenState {
pub input_tokens: i32,
pub output_tokens: i32,
pub total_tokens: i32,
pub accumulated_input_tokens: i32,
pub accumulated_output_tokens: i32,
pub accumulated_total_tokens: i32,
}

#[cfg(test)]
mod tests {
use crate::conversation::message::{Message, MessageContent, MessageMetadata};
Expand Down
23 changes: 17 additions & 6 deletions crates/goose/src/providers/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,11 @@ impl Add for Usage {
type Output = Self;

fn add(self, other: Self) -> Self {
Self {
input_tokens: sum_optionals(self.input_tokens, other.input_tokens),
output_tokens: sum_optionals(self.output_tokens, other.output_tokens),
total_tokens: sum_optionals(self.total_tokens, other.total_tokens),
}
Self::new(
sum_optionals(self.input_tokens, other.input_tokens),
sum_optionals(self.output_tokens, other.output_tokens),
sum_optionals(self.total_tokens, other.total_tokens),
)
}
}

Expand All @@ -298,10 +298,21 @@ impl Usage {
output_tokens: Option<i32>,
total_tokens: Option<i32>,
) -> Self {
let calculated_total = if total_tokens.is_none() {
match (input_tokens, output_tokens) {
(Some(input), Some(output)) => Some(input + output),
(Some(input), None) => Some(input),
(None, Some(output)) => Some(output),
(None, None) => None,
}
} else {
total_tokens
};

Self {
input_tokens,
output_tokens,
total_tokens,
total_tokens: calculated_total,
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions crates/goose/src/providers/formats/bedrock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,11 @@ pub fn from_bedrock_role(role: &bedrock::ConversationRole) -> Result<Role> {
}

pub fn from_bedrock_usage(usage: &bedrock::TokenUsage) -> Usage {
Usage {
input_tokens: Some(usage.input_tokens),
output_tokens: Some(usage.output_tokens),
total_tokens: Some(usage.total_tokens),
}
Usage::new(
Some(usage.input_tokens),
Some(usage.output_tokens),
Some(usage.total_tokens),
)
}

pub fn from_bedrock_json(document: &Document) -> Result<Value> {
Expand Down
10 changes: 5 additions & 5 deletions crates/goose/src/providers/sagemaker_tgi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,11 +307,11 @@ impl Provider for SageMakerTgiProvider {
let message = self.parse_tgi_response(response)?;

// TGI doesn't provide usage statistics, so we estimate
let usage = Usage {
input_tokens: Some(0), // Would need to tokenize input to get accurate count
output_tokens: Some(0), // Would need to tokenize output to get accurate count
total_tokens: Some(0),
};
let usage = Usage::new(
Some(0), // Would need to tokenize input to get accurate count
Some(0), // Would need to tokenize output to get accurate count
Some(0),
);

// Add debug trace
let debug_payload = serde_json::json!({
Expand Down
10 changes: 5 additions & 5 deletions crates/goose/src/providers/venice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,11 +508,11 @@ impl Provider for VeniceProvider {

// Extract usage
let usage_data = &response_json["usage"];
let usage = Usage {
input_tokens: usage_data["prompt_tokens"].as_i64().map(|v| v as i32),
output_tokens: usage_data["completion_tokens"].as_i64().map(|v| v as i32),
total_tokens: usage_data["total_tokens"].as_i64().map(|v| v as i32),
};
let usage = Usage::new(
usage_data["prompt_tokens"].as_i64().map(|v| v as i32),
usage_data["completion_tokens"].as_i64().map(|v| v as i32),
usage_data["total_tokens"].as_i64().map(|v| v as i32),
);

Ok((
Message::new(Role::Assistant, Utc::now().timestamp(), content),
Expand Down
Empty file removed openapi.json
Empty file.
41 changes: 41 additions & 0 deletions ui/desktop/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -3185,12 +3185,16 @@
"type": "object",
"required": [
"message",
"token_state",
"type"
],
"properties": {
"message": {
"$ref": "#/components/schemas/Message"
},
"token_state": {
"$ref": "#/components/schemas/TokenState"
},
"type": {
"type": "string",
"enum": [
Expand Down Expand Up @@ -4418,6 +4422,43 @@
}
}
},
"TokenState": {
"type": "object",
"required": [
"inputTokens",
"outputTokens",
"totalTokens",
"accumulatedInputTokens",
"accumulatedOutputTokens",
"accumulatedTotalTokens"
],
"properties": {
"accumulatedInputTokens": {
"type": "integer",
"format": "int32"
},
"accumulatedOutputTokens": {
"type": "integer",
"format": "int32"
},
"accumulatedTotalTokens": {
"type": "integer",
"format": "int32"
},
"inputTokens": {
"type": "integer",
"format": "int32"
},
"outputTokens": {
"type": "integer",
"format": "int32"
},
"totalTokens": {
"type": "integer",
"format": "int32"
}
}
},
"Tool": {
"type": "object",
"required": [
Expand Down
10 changes: 10 additions & 0 deletions ui/desktop/src/api/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ export type MessageContent = (TextContent & {

export type MessageEvent = {
message: Message;
token_state: TokenState;
type: 'Message';
} | {
error: string;
Expand Down Expand Up @@ -779,6 +780,15 @@ export type ThinkingContent = {
thinking: string;
};

export type TokenState = {
accumulatedInputTokens: number;
accumulatedOutputTokens: number;
accumulatedTotalTokens: number;
inputTokens: number;
outputTokens: number;
totalTokens: number;
};

export type Tool = {
annotations?: ToolAnnotations | {
[key: string]: unknown;
Expand Down
11 changes: 8 additions & 3 deletions ui/desktop/src/components/BaseChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ function BaseChatContent({
sessionOutputTokens,
localInputTokens,
localOutputTokens,
tokenState,
commandHistory,
toolCallNotifications,
sessionMetadata,
Expand Down Expand Up @@ -442,9 +443,13 @@ function BaseChatContent({
commandHistory={commandHistory}
initialValue={input || ''}
setView={setView}
numTokens={sessionTokenCount}
inputTokens={sessionInputTokens || localInputTokens}
outputTokens={sessionOutputTokens || localOutputTokens}
totalTokens={tokenState?.totalTokens ?? sessionTokenCount}
accumulatedInputTokens={
tokenState?.accumulatedInputTokens ?? sessionInputTokens ?? localInputTokens
}
accumulatedOutputTokens={
tokenState?.accumulatedOutputTokens ?? sessionOutputTokens ?? localOutputTokens
}
droppedFiles={droppedFiles}
onFilesProcessed={() => setDroppedFiles([])} // Clear dropped files after processing
messages={messages}
Expand Down
Loading