Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f87c4d7
chore: update canonical models json (#11641)
kalvinnchau Aug 28, 2026
dd8f5ed
chore(acp): remove unused unstable methods (#11650)
lifeizhou-ap Aug 28, 2026
2f5ff48
Clean up obsolete extension paths before redesigning the extension ma…
DOsinga Aug 28, 2026
cfc0538
fix(providers): parse OpenRouter nested cache_write_tokens in usage (…
filipkujawa Aug 28, 2026
a6d0b10
feat(gdk): expose cached input-token usage metrics (#11628)
alexhancock Aug 28, 2026
a9060fd
docs: stop enumerating crates in AGENTS.md Structure (#11614)
Wolfe-Jam Aug 28, 2026
ef0924a
feat(gdk): publish Linux ARM64 native artifacts (#11634)
alexhancock Aug 28, 2026
8ae4e4b
fix(ui): render untagged fenced code blocks as proper code blocks (#1…
jramnani Aug 28, 2026
815bd0b
feat(cli): add --system flag to goose session for parity with goose r…
michaelneale Aug 31, 2026
fb15d4e
feat: configurable Anthropic prompt-cache TTL (5m/1h) (#11576)
michaelneale Aug 31, 2026
2163c14
test: remove racy scheduler message count assertion (#11691)
Alphaxiaoteng Aug 31, 2026
3a1d7f8
refactor(acp): remove unused provider list fields (#11696)
lifeizhou-ap Aug 31, 2026
5dc3fa8
fix(apps): protect bundled cache identities (#11397)
jbg Aug 31, 2026
7d97fe1
feat(gdk): preserve thinking and redacted-thinking blocks across turn…
alexhancock Aug 31, 2026
38816df
fix(desktop): configure proxy for renderer session (#11708)
jbg Aug 31, 2026
5c748fe
feat(gdk): add structured request and response observability hooks (#…
alexhancock Aug 31, 2026
65415f3
chore(deps): bump actions/checkout from 7.0.0 to 7.0.1 (#11660)
dependabot[bot] Aug 31, 2026
e52be07
fix(desktop): pin FormatJS CLI for Intel macOS (#11639)
jamadeo Aug 31, 2026
a9f68b4
chore(deps): bump Swatinem/rust-cache from 2.9.1 to 2.9.2 (#11662)
dependabot[bot] Aug 31, 2026
4550a2e
chore(deps): bump github/codeql-action from 4.37.6 to 4.37.8 (#11661)
dependabot[bot] Aug 31, 2026
1d01466
feat(gdk): expose Anthropic response metadata for observability (#11630)
alexhancock Aug 31, 2026
114250f
fix(gdk): preserve tool-call indices in streaming responses (#11637)
alexhancock Aug 31, 2026
ed9648b
fix(security): restrict extension tool dispatch (#11602)
jbg Aug 31, 2026
5345d05
fixed 24 hour locale system bug (#11719)
RaghavBhardwaj18 Aug 31, 2026
35897f6
chore(deps): bump actions/setup-java from 5.7.0 to 6.0.0 (#11659)
dependabot[bot] Sep 1, 2026
0a9749b
feat(auth): enable refresh auth cli (#11657)
Darkflame72 Sep 1, 2026
7c7dc34
fix(dictation): bound provider response bodies (#11401)
jbg Sep 1, 2026
34898f1
fix(desktop): reject oversized recipe files before reading (#11404)
jbg Sep 1, 2026
9a5319a
fix(security): isolate audio recorder generations (#11456)
jbg Sep 1, 2026
e05f5d4
fix(security): fuse command scanner signals (#11440)
jbg Sep 1, 2026
0cf7882
fix(security): isolate Telegram voice temp files (#11442)
jbg Sep 1, 2026
7d650eb
fix(security): anchor execute shell extraction (#11492)
jbg Sep 1, 2026
c1646b8
fix(gdk): repair uniffi build broken by semantic merge conflict (#11721)
alexhancock Sep 1, 2026
4ad43df
fix(desktop): keep unsent chat input across navigation (#11494)
TheSeydiCharyyev Sep 1, 2026
dcfc581
feat(aimlapi): add the AI/ML API provider and a PKCE sign-in
Lookoff-AIMLAPI Sep 1, 2026
a5f94f6
feat(aimlapi): ship goose's own partner id
Lookoff-AIMLAPI Sep 1, 2026
801d87a
feat(aimlapi): send the attribution headers on every request
Lookoff-AIMLAPI Sep 1, 2026
fa6192e
Merge the AI/ML API provider rework into the fork
Lookoff-AIMLAPI Sep 1, 2026
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
57 changes: 53 additions & 4 deletions .github/workflows/maven-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ jobs:
os: ubuntu-latest
container: quay.io/pypa/manylinux_2_28_x86_64@sha256:441c35fdc6ee809ff9260894f8468ab4fea8c15dc880f8700a3f81b7922c1cda
resource-prefix: linux-x86-64
- name: linux-aarch64
os: ubuntu-22.04-arm
container: quay.io/pypa/manylinux_2_28_aarch64@sha256:8b5f2b4e8c072ae5aefeb659f22c03e1ff46e6a82f154b6c904b106c87e65ff7
resource-prefix: linux-aarch64
- name: win32-x86-64
os: windows-latest
resource-prefix: win32-x86-64
Expand All @@ -40,7 +44,7 @@ jobs:
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1

- name: Cache Cargo artifacts
uses: Swatinem/rust-cache@258712b0b7b1ddf8bddc9fc3b0faca682b2736c3 # v2
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2

- name: Build native library
shell: bash
Expand Down Expand Up @@ -77,7 +81,7 @@ jobs:
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1

- name: Set up Java
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
with:
distribution: temurin
java-version: "17"
Expand Down Expand Up @@ -122,9 +126,54 @@ jobs:
path: maven-artifacts/**
if-no-files-found: error

smoke-test-linux-aarch64:
name: Smoke test Kotlin GDK (linux-aarch64)
needs: package
runs-on: ubuntu-22.04-arm
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Set up Java
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
with:
distribution: temurin
java-version: "17"

- name: Set up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0

- name: Download Maven artifact bundle
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: goose-sdk-maven
path: maven-artifacts

- name: Install Maven artifact bundle into local repository
shell: bash
run: |
version=$(grep -m1 '^version =' crates/goose-sdk/Cargo.toml | sed -E 's/version = "([^"]+)"/\1/')
target="$HOME/.m2/repository/io/github/aaif-goose/gdk/$version"
mkdir -p "$target"
find maven-artifacts -type f -exec cp {} "$target/" +

- name: Load native library in an ARM64 JVM
shell: bash
working-directory: crates/goose-sdk/examples/uniffi/kotlin
run: |
gradle --no-daemon installDist
cat > "$RUNNER_TEMP/LoadNativeLibrary.java" <<'JAVA'
public class LoadNativeLibrary {
public static void main(String[] args) {
System.out.println(io.github.aaif_goose.GooseKt.openaiDefaultModel());
}
}
JAVA
java -cp "$(find build/install -name '*.jar' | paste -sd: -)" "$RUNNER_TEMP/LoadNativeLibrary.java"

publish:
name: Publish to Maven Central
needs: package
needs: [package, smoke-test-linux-aarch64]
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && inputs.publish
environment: maven-central
Expand All @@ -136,7 +185,7 @@ jobs:
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1

- name: Set up Java
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
with:
distribution: temurin
java-version: "17"
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/mcp-conformance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1.17.0

Expand All @@ -28,7 +28,7 @@ jobs:
sudo apt install -y libdbus-1-dev libxcb1-dev

- name: Cache Cargo artifacts
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
key: mcp-conformance

Expand Down Expand Up @@ -67,7 +67,7 @@ jobs:
baseline: "crates/goose-cli/tests/mcp-conformance/expected-failures-2026-07-28-0.2.0-alpha.10.yaml"
steps:
- name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Install Dependencies
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@v4.37.6
uses: github/codeql-action/upload-sarif@v4.37.8
with:
sarif_file: results.sarif
12 changes: 3 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,9 @@ cd ui/desktop && pnpm test # test UI

## Structure
```
crates/
├── goose # core logic
├── goose-acp-macros # ACP proc macros
├── goose-cli # CLI entry
├── goose-mcp # MCP extensions
├── goose-test # test utilities
└── goose-test-support # test helpers

ui/desktop/ # Electron app
crates/ # Rust workspace members — see root Cargo.toml (`members = ["crates/*"]`)
ui/desktop/ # Electron app
ui/text/ # deprecated ACP TUI (see ui/text/README.md)
```

## Development Loop
Expand Down
4 changes: 1 addition & 3 deletions crates/goose-agent/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,7 @@ pub fn ends_turn(messages: &[Message]) -> bool {
&& !last.content.iter().any(|content| {
matches!(
content,
MessageContent::ToolRequest(_)
| MessageContent::FrontendToolRequest(_)
| MessageContent::ActionRequired(_)
MessageContent::ToolRequest(_) | MessageContent::ActionRequired(_)
)
})
})
Expand Down
28 changes: 27 additions & 1 deletion crates/goose-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,15 @@ enum Command {
)]
history: bool,

/// Additional system prompt to customize agent behavior
#[arg(
long = "system",
value_name = "TEXT",
help = "Additional system prompt to customize agent behavior",
long_help = "Provide additional system instructions to customize the agent's behavior"
)]
system: Option<String>,

#[command(flatten)]
session_opts: SessionOptions,

Expand Down Expand Up @@ -1983,6 +1992,7 @@ struct InteractiveSessionArgs {
fork: bool,
edit: bool,
history: bool,
system: Option<String>,
session_opts: SessionOptions,
extension_opts: ExtensionOptions,
model_opts: ModelOptions,
Expand All @@ -1995,6 +2005,7 @@ async fn handle_interactive_session(args: InteractiveSessionArgs) -> Result<()>
fork,
edit,
history,
system,
session_opts,
extension_opts,
model_opts,
Expand Down Expand Up @@ -2072,7 +2083,7 @@ async fn handle_interactive_session(args: InteractiveSessionArgs) -> Result<()>
builtins: extension_opts.builtins,
no_profile: extension_opts.no_profile,
recipe: None,
additional_system_prompt: None,
additional_system_prompt: system,
provider: model_opts.provider,
model: model_opts.model,
debug: session_opts.debug,
Expand Down Expand Up @@ -2851,6 +2862,7 @@ pub async fn cli() -> anyhow::Result<()> {
fork,
edit,
history,
system,
session_opts,
extension_opts,
model_opts,
Expand All @@ -2861,6 +2873,7 @@ pub async fn cli() -> anyhow::Result<()> {
fork,
edit,
history,
system,
session_opts,
extension_opts,
model_opts,
Expand Down Expand Up @@ -3034,6 +3047,19 @@ mod tests {
}
}

#[test]
fn session_accepts_system_prompt() {
let cli = Cli::try_parse_from(["goose", "session", "--system", "extra instructions"])
.expect("system prompt should work for a new session");

match cli.command {
Some(Command::Session { system, .. }) => {
assert_eq!(system.as_deref(), Some("extra instructions"));
}
_ => panic!("expected session command"),
}
}

#[test]
fn nushell_completion_generation_emits_module() {
let mut cmd = Cli::command();
Expand Down
106 changes: 100 additions & 6 deletions crates/goose-cli/src/commands/configure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use goose::agents::Agent;
use goose::agents::{extension::Envs, ExtensionConfig};
use goose::config::declarative_providers::{
create_custom_provider, remove_custom_provider, CreateCustomProviderParams,
create_custom_provider, remove_custom_provider, AuthConfig, CreateCustomProviderParams,
};
use goose::config::extensions::{
get_all_extension_names, get_all_extensions, get_enabled_extensions, get_extension_by_name,
Expand Down Expand Up @@ -249,6 +249,10 @@
"Sign in with Tetrate Agent Router Service to automatically configure models",
)
.item(
"aimlapi",

Check warning on line 252 in crates/goose-cli/src/commands/configure.rs

View workflow job for this annotation

GitHub Actions / Check Rust Code Format

Diff in /home/runner/work/goose-aimlapi/goose-aimlapi/crates/goose-cli/src/commands/configure.rs
"AI/ML API Login",
"Sign in with AI/ML API to automatically configure models",
) .item(
"manual",
"Manual Configuration",
"Choose a provider and enter credentials manually",
Expand Down Expand Up @@ -276,6 +280,18 @@
);
}
}
"aimlapi" => {
if let Err(e) = handle_aimlapi_auth().await {
let _ = config.clear();
println!(
"
{} AI/ML API sign-in failed: {}
Please try again or use manual configuration",
style("Error").red().italic(),
e,
);
}
}
"manual" => handle_manual_provider_setup(config).await,
_ => unreachable!(),
}
Expand Down Expand Up @@ -1949,6 +1965,26 @@
Ok(())
}

/// Handle AI/ML API authentication (authorization code + PKCE)
pub async fn handle_aimlapi_auth() -> anyhow::Result<()> {
use goose::config::{configure_aimlapi, signup_aimlapi::AimlapiAuth};

Check warning on line 1971 in crates/goose-cli/src/commands/configure.rs

View workflow job for this annotation

GitHub Actions / Check Rust Code Format

Diff in /home/runner/work/goose-aimlapi/goose-aimlapi/crates/goose-cli/src/commands/configure.rs
let mut auth_flow = AimlapiAuth::new()?;
let api_key = auth_flow.complete_flow().await?;
println!("
Sign-in complete!");

let config = Config::global();

println!("

Check warning on line 1979 in crates/goose-cli/src/commands/configure.rs

View workflow job for this annotation

GitHub Actions / Check Rust Code Format

Diff in /home/runner/work/goose-aimlapi/goose-aimlapi/crates/goose-cli/src/commands/configure.rs
Configuring AI/ML API...");
configure_aimlapi(config, api_key)?;

println!("AI/ML API configuration complete");

Ok(())
}

/// Handle OpenRouter authentication
pub async fn handle_openrouter_auth() -> anyhow::Result<()> {
use goose::config::{configure_openrouter, signup_openrouter::OpenRouterAuth};
Expand Down Expand Up @@ -2198,11 +2234,68 @@
.initial_value(true)
.interact()?;

let api_key: String = if requires_auth {
cliclack::password("API key:").mask('▪').interact()?
} else {
String::new()
};
let mut api_key = String::new();
let mut auth: Option<AuthConfig> = None;

if requires_auth {
let auth_mode = cliclack::select("How should goose obtain credentials for this provider?")
.item("static", "Static API key", "Enter a fixed API key now")
.item(
"command",
"Command (refreshable)",
"Run a command to fetch/refresh a short-lived credential",
)
.interact()?;

if auth_mode == "command" {
let command: String = cliclack::input("Command to run for the credential:")
.placeholder("/path/to/get-token.sh")
.validate(|input: &String| {
if input.trim().is_empty() {
Err("Please enter a command")
} else {
Ok(())
}
})
.interact()?;

let args_input: String =
cliclack::input("Command arguments (comma-separated, optional):")
.placeholder("--flag, value")
.required(false)
.interact()?;
let args: Vec<String> = args_input
.split(',')
.map(str::trim)
.filter(|arg| !arg.is_empty())
.map(str::to_string)
.collect();

let refresh_interval_input: String = cliclack::input(
"Refresh interval in seconds (0 to only refresh after an auth failure):",
)
.default_input("3600")
.validate(|input: &String| {
input
.trim()
.parse::<u64>()
.map(|_| ())
.map_err(|_| "Please enter a whole number of seconds")
})
.interact()?;
let refresh_interval: u64 = refresh_interval_input.trim().parse().unwrap_or(3600);

auth = Some(AuthConfig {
command,
args,
refresh_interval,
timeout_seconds: None,
cwd: None,
});
} else {
api_key = cliclack::password("API key:").mask('▪').interact()?;
}
}

let models_input: String = cliclack::input("Available models (separate with commas):")
.placeholder("model-a, model-b, model-c")
Expand Down Expand Up @@ -2251,6 +2344,7 @@
catalog_provider_id: None,
base_path,
preserves_thinking: None,
auth,
})?;

if !provider_config.models.is_empty() {
Expand Down
1 change: 0 additions & 1 deletion crates/goose-cli/src/scenario_tests/scenario_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,6 @@ where
},
Arc::new(mock_client),
None,
None,
)
.await;

Expand Down
Loading
Loading