sigit-code 1.7.4__tar.gz → 1.7.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sigit_code-1.7.4 → sigit_code-1.7.6}/Cargo.lock +2 -2
- {sigit_code-1.7.4 → sigit_code-1.7.6}/Cargo.toml +2 -2
- {sigit_code-1.7.4 → sigit_code-1.7.6}/PKG-INFO +1 -1
- sigit_code-1.7.6/crates/cli/README.md +90 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/account.rs +4 -39
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/backend.rs +27 -3
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/chat.rs +27 -6
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/headless.rs +9 -6
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/main.rs +502 -130
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/permissions.rs +3 -1
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/provider.rs +11 -1
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/tools.rs +350 -11
- sigit_code-1.7.6/crates/cli/tests/acp_cloud_reauth.rs +208 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_logout.rs +71 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_permissions.rs +73 -1
- sigit_code-1.7.4/crates/cli/README.md +0 -234
- {sigit_code-1.7.4 → sigit_code-1.7.6}/README.md +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/Cargo.toml +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/client_fs.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/client_terminal.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/commands.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/frontmatter.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/harness_markup.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/hooks.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/inline_tool_calls.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/instructions.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/mcp.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/models.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/program_status.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/repetition.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/session_store.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/settings.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/setup.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/skills.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/subagents.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/src/workspace.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_audio.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_client_fs.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_client_terminal.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_concurrent_sessions.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_elicitation.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_embedded_context.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_endpoint_errors.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_error_codes.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_harness_markup.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_images.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_multi_root.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_session_list.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_session_load.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_stop_reasons.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_tool_call_name.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/acp_tool_stdin.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/headless_mode.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/cli/tests/version_flag.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/sigit-agent/Cargo.toml +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/sigit-agent/README.md +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/sigit-agent/assets/sign-in-logo.png +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/sigit-agent/src/auth.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/sigit-agent/src/browser_auth.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/sigit-agent/src/credentials.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/sigit-agent/src/lib.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/sigit-agent/src/profile.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/sigit-agent/src/prompt.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/crates/sigit-agent/tests/embedded.rs +0 -0
- {sigit_code-1.7.4 → sigit_code-1.7.6}/pyproject.toml +0 -0
|
@@ -5945,7 +5945,7 @@ checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
|
|
5945
5945
|
|
|
5946
5946
|
[[package]]
|
|
5947
5947
|
name = "sigit"
|
|
5948
|
-
version = "1.7.
|
|
5948
|
+
version = "1.7.6"
|
|
5949
5949
|
dependencies = [
|
|
5950
5950
|
"agent-client-protocol",
|
|
5951
5951
|
"anyhow",
|
|
@@ -5976,7 +5976,7 @@ dependencies = [
|
|
|
5976
5976
|
|
|
5977
5977
|
[[package]]
|
|
5978
5978
|
name = "sigit-agent"
|
|
5979
|
-
version = "1.7.
|
|
5979
|
+
version = "1.7.6"
|
|
5980
5980
|
dependencies = [
|
|
5981
5981
|
"agent-client-protocol",
|
|
5982
5982
|
"anyhow",
|
|
@@ -3,7 +3,7 @@ resolver = "3"
|
|
|
3
3
|
members = ["crates/cli", "crates/sigit-*"]
|
|
4
4
|
|
|
5
5
|
[workspace.package]
|
|
6
|
-
version = "1.7.
|
|
6
|
+
version = "1.7.6"
|
|
7
7
|
edition = "2024"
|
|
8
8
|
license = "Apache-2.0"
|
|
9
9
|
repository = "https://github.com/getsigit/sigit"
|
|
@@ -16,7 +16,7 @@ authors = ["Seto Elkahfi <seto@sigit.si>", "paydii <193906237+paydii@users.norep
|
|
|
16
16
|
# crates.io, so this resolves from the registry rather than the onde-ed checkout next door.
|
|
17
17
|
ed-acp = { version = "1.3.0", default-features = false }
|
|
18
18
|
ed-acp-testkit = "1.3.0"
|
|
19
|
-
sigit-agent = { version = "1.7.
|
|
19
|
+
sigit-agent = { version = "1.7.6", default-features = false, path = "crates/sigit-agent" }
|
|
20
20
|
|
|
21
21
|
# ACP protocol SDK
|
|
22
22
|
agent-client-protocol = { version = "2.2", features = ["unstable_session_fork"] }
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/logo.png" alt="siGit Code" width="96">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">siGit Code</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><strong>The coding agent that runs where your code lives.</strong></p>
|
|
8
|
+
<p align="center">A modular on-device inference LLM coding agent. Core component of siGit Factory.</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://crates.io/crates/sigit"><img src="https://img.shields.io/crates/v/sigit?style=flat-square&labelColor=17211D&color=235843" alt="Crates.io"></a>
|
|
12
|
+
<a href="https://pypi.org/project/sigit-code/"><img src="https://img.shields.io/pypi/v/sigit-code?style=flat-square&labelColor=17211D&color=235843" alt="PyPI"></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/@getsigit/sigit"><img src="https://img.shields.io/npm/v/@getsigit/sigit?style=flat-square&labelColor=17211D&color=235843" alt="npm"></a>
|
|
14
|
+
<a href="https://snapcraft.io/sigit"><img src="https://snapcraft.io/sigit/badge.svg" alt="sigit"></a>
|
|
15
|
+
<a href="https://sigit.si/code"><img src="https://img.shields.io/badge/sigit.si%2Fcode-235843?style=flat-square&labelColor=17211D" alt="Website"></a>
|
|
16
|
+
<a href="https://github.com/getsigit/sigit/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-235843?style=flat-square&labelColor=17211D" alt="License"></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="https://www.nuget.org/packages/SiGit.Code"><img src="https://img.shields.io/nuget/v/SiGit.Code?style=flat-square&labelColor=17211D&color=235843&label=nuget" alt="NuGet"></a>
|
|
21
|
+
<a href="https://github.com/microsoft/winget-pkgs/tree/master/manifests/g/getSigit/siGitCode"><img src="https://img.shields.io/winget/v/getSigit.siGitCode?style=flat-square&labelColor=17211D&color=235843" alt="winget"></a>
|
|
22
|
+
<a href="https://marketplace.visualstudio.com/items?itemName=getsigit.sigit-code"><img src="https://img.shields.io/badge/VS%20Code-Marketplace-235843?style=flat-square&labelColor=17211D" alt="VS Code Marketplace"></a>
|
|
23
|
+
<a href="https://pypi.org/project/sigit-code/"><img src="https://img.shields.io/pypi/dm/sigit-code?style=flat-square&labelColor=17211D&color=235843&label=pypi%20downloads" alt="PyPI downloads"></a>
|
|
24
|
+
<a href="https://github.com/getsigit/sigit/releases"><img src="https://img.shields.io/github/v/release/getsigit/sigit?style=flat-square&labelColor=17211D&color=235843" alt="Release"></a>
|
|
25
|
+
<a href="https://github.com/getsigit/sigit/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/getsigit/sigit/ci.yml?style=flat-square&labelColor=17211D&label=ci" alt="CI"></a>
|
|
26
|
+
<a href="https://github.com/getsigit/sigit/releases"><img src="https://img.shields.io/github/downloads/getsigit/sigit/total?style=flat-square&labelColor=17211D&color=235843" alt="GitHub downloads"></a>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
siGit Code runs on your machine and works in any codebase. Inference runs on-device by default through the [Onde Inference on-device inference SDK](https://ondeinference.com/sdk), or on siGit Code Cloud when you choose it. You need no API key to start, and it works with any editor that speaks the [Agent Client Protocol](https://agentclientprotocol.com). The agent is Apache-2.0. siGit Code Cloud and [siGit Factory](https://factory.sigit.si/) are the hosted, paid side.
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
cargo install sigit
|
|
35
|
+
brew tap getsigit/tap && brew trust --tap getsigit/tap && brew install sigit
|
|
36
|
+
npm install -g @getsigit/sigit
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
More ways, including pip, NuGet, winget, Scoop and Linux packages, are in [docs/install.md](docs/install.md).
|
|
40
|
+
|
|
41
|
+
## Get siGit anywhere
|
|
42
|
+
|
|
43
|
+
The command-line agent and the desktop and mobile app are separate products. Each cell links to where it ships.
|
|
44
|
+
|
|
45
|
+
| Desktop and mobile apps | macOS | Windows | Linux | iOS | Android |
|
|
46
|
+
|---|:-:|:-:|:-:|:-:|:-:|
|
|
47
|
+
| [App Store](https://apps.apple.com/app/id6753018849) | [✓](https://apps.apple.com/app/id6753018849) | | | [✓](https://apps.apple.com/app/id6753018849) | |
|
|
48
|
+
| [Google Play](https://play.google.com/store/apps/details?id=xyz.smbcloud.SiGit) | | | | | [✓](https://play.google.com/store/apps/details?id=xyz.smbcloud.SiGit) |
|
|
49
|
+
| [Microsoft Store](https://apps.microsoft.com/detail/9p69ph1k7nxx) | | [✓](https://apps.microsoft.com/detail/9p69ph1k7nxx) | | | |
|
|
50
|
+
| [Snap Store](https://snapcraft.io/sigit) | | | [✓](https://snapcraft.io/sigit) | | |
|
|
51
|
+
| [Direct download](https://getsigit.5mb.app/download) | [✓](https://getsigit.5mb.app/download) | [✓](https://getsigit.5mb.app/download) | [✓](https://getsigit.5mb.app/download) | | |
|
|
52
|
+
|
|
53
|
+
| Command line | macOS | Windows | Linux |
|
|
54
|
+
|---|:-:|:-:|:-:|
|
|
55
|
+
| [crates.io](https://crates.io/crates/sigit) | ✓ | ✓ | ✓ |
|
|
56
|
+
| [Homebrew](docs/install.md) | ✓ | | |
|
|
57
|
+
| [npm](https://www.npmjs.com/package/@getsigit/sigit) | ✓ | ✓ | ✓ |
|
|
58
|
+
| [PyPI and uv](https://pypi.org/project/sigit-code/) | ✓ | ✓ | ✓ |
|
|
59
|
+
| [NuGet](https://www.nuget.org/packages/SiGit.Code) | ✓ | ✓ | ✓ |
|
|
60
|
+
| [winget](docs/install.md) | | ✓ | |
|
|
61
|
+
| [Scoop](https://github.com/getsigit/scoop-bucket) | | ✓ | |
|
|
62
|
+
| [deb and rpm](https://github.com/getsigit/sigit/releases) | | | ✓ |
|
|
63
|
+
|
|
64
|
+
`sudo snap install sigit` installs the desktop app, not the terminal agent. The app currently uses siGit Code Cloud for inference, while the command line runs models on-device. Details are in [docs/distribution.md](docs/distribution.md).
|
|
65
|
+
|
|
66
|
+
Every channel, kept current: https://getsigit.5mb.app/
|
|
67
|
+
|
|
68
|
+
## Use it your way
|
|
69
|
+
|
|
70
|
+
- **In your editor.** Any ACP client starts `sigit --acp`. See [ACP support](docs/acp.md).
|
|
71
|
+
- **In the terminal.** Run `sigit` for a full-screen chat UI. See [terminal mode](docs/terminal.md).
|
|
72
|
+
- **In scripts and CI.** `sigit run "<prompt>"` gives you JSONL events and exit codes. See [headless mode](docs/headless.md).
|
|
73
|
+
|
|
74
|
+
Setup guides for Zed, Xcode, VS Code and the JetBrains IDEs are in [docs/editors.md](docs/editors.md).
|
|
75
|
+
|
|
76
|
+
## Docs
|
|
77
|
+
|
|
78
|
+
[Install](docs/install.md), [editors](docs/editors.md), [ACP](docs/acp.md), [terminal](docs/terminal.md), [headless](docs/headless.md), [hooks](docs/hooks.md), [MCP](docs/mcp.md), [telemetry](docs/telemetry.md), [distribution](docs/distribution.md). The index is [docs/README.md](docs/README.md).
|
|
79
|
+
|
|
80
|
+
## Contributing
|
|
81
|
+
|
|
82
|
+
Issues and pull requests are welcome. Open one against `development`.
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
[Apache 2.0](https://github.com/getsigit/sigit/blob/main/LICENSE)
|
|
87
|
+
|
|
88
|
+
## Copyright
|
|
89
|
+
|
|
90
|
+
© 2026 [siGit Code & Deploy](https://sigit.si).
|
|
@@ -27,7 +27,7 @@ fn api_base() -> String {
|
|
|
27
27
|
// `serde_json::Value` rather than a struct because of the bare-string variant.
|
|
28
28
|
|
|
29
29
|
#[derive(Debug, Deserialize)]
|
|
30
|
-
struct
|
|
30
|
+
struct UserResponse {
|
|
31
31
|
#[serde(default)]
|
|
32
32
|
email: Option<String>,
|
|
33
33
|
}
|
|
@@ -90,40 +90,6 @@ pub async fn authenticate(email: &str, password: &str) -> Result<String, String>
|
|
|
90
90
|
Err(format!("sign-in failed: {message}"))
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
/// Verify that a usable session exists, confirming the stored token against the
|
|
94
|
-
/// account API. Returns the signed-in email on success, or a human-readable
|
|
95
|
-
/// reason it is not usable. Used by the ACP `authenticate` handler to answer the
|
|
96
|
-
/// editor's auth gate.
|
|
97
|
-
pub async fn verify_session() -> Result<String, String> {
|
|
98
|
-
let Some(creds) = credentials::load() else {
|
|
99
|
-
return Err("not signed in".to_string());
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
let url = format!("{}/api/v1/me", api_base().trim_end_matches('/'));
|
|
103
|
-
let response = reqwest::Client::new()
|
|
104
|
-
.get(&url)
|
|
105
|
-
.bearer_auth(&creds.access_token)
|
|
106
|
-
.send()
|
|
107
|
-
.await
|
|
108
|
-
.map_err(|error| format!("could not reach siGit Code Cloud: {error}"))?;
|
|
109
|
-
|
|
110
|
-
if response.status().is_success() {
|
|
111
|
-
let email = response
|
|
112
|
-
.json::<MeResponse>()
|
|
113
|
-
.await
|
|
114
|
-
.ok()
|
|
115
|
-
.and_then(|me| me.email)
|
|
116
|
-
.or(creds.email)
|
|
117
|
-
.unwrap_or_else(|| "(unknown)".to_string());
|
|
118
|
-
Ok(email)
|
|
119
|
-
} else {
|
|
120
|
-
Err(format!(
|
|
121
|
-
"session expired (HTTP {})",
|
|
122
|
-
response.status().as_u16()
|
|
123
|
-
))
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
93
|
/// Run an interactive sign-in against the terminal, prompting for email and a
|
|
128
94
|
/// hidden password. Used by `sigit login`, which the editor launches in an
|
|
129
95
|
/// embedded terminal for ACP terminal-based authentication. Returns the signed-in
|
|
@@ -166,11 +132,10 @@ pub async fn end_session() -> String {
|
|
|
166
132
|
/// One-line description of the current session, verifying the token if reachable.
|
|
167
133
|
pub async fn status_line() -> String {
|
|
168
134
|
let Some(creds) = credentials::load() else {
|
|
169
|
-
return "Not signed in. Use `/login
|
|
170
|
-
.to_string();
|
|
135
|
+
return "Not signed in. Use `/login` to use siGit Code Cloud.".to_string();
|
|
171
136
|
};
|
|
172
137
|
|
|
173
|
-
let url = format!("{}/api/v1/
|
|
138
|
+
let url = format!("{}/api/v1/user", api_base().trim_end_matches('/'));
|
|
174
139
|
match reqwest::Client::new()
|
|
175
140
|
.get(&url)
|
|
176
141
|
.bearer_auth(&creds.access_token)
|
|
@@ -179,7 +144,7 @@ pub async fn status_line() -> String {
|
|
|
179
144
|
{
|
|
180
145
|
Ok(response) if response.status().is_success() => {
|
|
181
146
|
let email = response
|
|
182
|
-
.json::<
|
|
147
|
+
.json::<UserResponse>()
|
|
183
148
|
.await
|
|
184
149
|
.ok()
|
|
185
150
|
.and_then(|me| me.email)
|
|
@@ -951,6 +951,9 @@ fn onde_result_to_turn(result: onde::inference::ToolAwareResult) -> TurnResult {
|
|
|
951
951
|
pub struct OpenAiBackend {
|
|
952
952
|
base_url: String,
|
|
953
953
|
api_key: String,
|
|
954
|
+
/// Read the bearer from the stored session on each request instead of
|
|
955
|
+
/// using `api_key`; see `bearer`.
|
|
956
|
+
session_token: bool,
|
|
954
957
|
model: String,
|
|
955
958
|
http: reqwest::Client,
|
|
956
959
|
/// The full message list sent on each request (system + turns + tool results).
|
|
@@ -985,6 +988,7 @@ impl OpenAiBackend {
|
|
|
985
988
|
Self {
|
|
986
989
|
base_url: base_url.into(),
|
|
987
990
|
api_key: api_key.into(),
|
|
991
|
+
session_token: false,
|
|
988
992
|
accepts_images: crate::provider::model_accepts_images(&model),
|
|
989
993
|
accepts_audio: crate::provider::model_accepts_audio(&model),
|
|
990
994
|
model,
|
|
@@ -994,6 +998,25 @@ impl OpenAiBackend {
|
|
|
994
998
|
}
|
|
995
999
|
}
|
|
996
1000
|
|
|
1001
|
+
/// Have the backend send the stored siGit Code Cloud session token as its
|
|
1002
|
+
/// bearer, read on every request. A token captured at build time goes
|
|
1003
|
+
/// stale when the user signs in as someone else; `api_key` is then only
|
|
1004
|
+
/// the fallback for a signed-out request.
|
|
1005
|
+
pub fn with_session_token(mut self, on: bool) -> Self {
|
|
1006
|
+
self.session_token = on;
|
|
1007
|
+
self
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
/// The bearer for the next request.
|
|
1011
|
+
fn bearer(&self) -> String {
|
|
1012
|
+
if self.session_token
|
|
1013
|
+
&& let Some(token) = crate::credentials::load_token()
|
|
1014
|
+
{
|
|
1015
|
+
return token;
|
|
1016
|
+
}
|
|
1017
|
+
self.api_key.clone()
|
|
1018
|
+
}
|
|
1019
|
+
|
|
997
1020
|
fn tools_json(tools: &[ToolSpec]) -> Vec<serde_json::Value> {
|
|
998
1021
|
tools
|
|
999
1022
|
.iter()
|
|
@@ -1122,7 +1145,7 @@ impl OpenAiBackend {
|
|
|
1122
1145
|
let mut response = self
|
|
1123
1146
|
.http
|
|
1124
1147
|
.post(&url)
|
|
1125
|
-
.bearer_auth(
|
|
1148
|
+
.bearer_auth(self.bearer())
|
|
1126
1149
|
.json(&body)
|
|
1127
1150
|
.send()
|
|
1128
1151
|
.await
|
|
@@ -1144,7 +1167,7 @@ impl OpenAiBackend {
|
|
|
1144
1167
|
response = self
|
|
1145
1168
|
.http
|
|
1146
1169
|
.post(&url)
|
|
1147
|
-
.bearer_auth(
|
|
1170
|
+
.bearer_auth(self.bearer())
|
|
1148
1171
|
.json(&body)
|
|
1149
1172
|
.send()
|
|
1150
1173
|
.await
|
|
@@ -1193,7 +1216,7 @@ impl OpenAiBackend {
|
|
|
1193
1216
|
let response = self
|
|
1194
1217
|
.http
|
|
1195
1218
|
.post(&url)
|
|
1196
|
-
.bearer_auth(
|
|
1219
|
+
.bearer_auth(self.bearer())
|
|
1197
1220
|
.json(&body)
|
|
1198
1221
|
.send()
|
|
1199
1222
|
.await
|
|
@@ -1826,6 +1849,7 @@ impl InferenceBackend for OpenAiBackend {
|
|
|
1826
1849
|
Some(Arc::new(Self {
|
|
1827
1850
|
base_url: self.base_url.clone(),
|
|
1828
1851
|
api_key: self.api_key.clone(),
|
|
1852
|
+
session_token: self.session_token,
|
|
1829
1853
|
model: self.model.clone(),
|
|
1830
1854
|
// The client is a handle on one connection pool; sharing it keeps
|
|
1831
1855
|
// connections to the endpoint warm across sessions.
|
|
@@ -167,6 +167,13 @@ pub(crate) fn tool_title(name: &str, arguments_json: &str) -> String {
|
|
|
167
167
|
str_arg("path")
|
|
168
168
|
}
|
|
169
169
|
"search_files" | "glob" => str_arg("pattern"),
|
|
170
|
+
"command_output" | "monitor_command" | "kill_command" => {
|
|
171
|
+
let id = args.as_ref().and_then(|a| a.get("task_id")?.as_u64());
|
|
172
|
+
id.map(|id| match crate::tools::background_task_command(id) {
|
|
173
|
+
Some(command) => format!("task {id} (`{command}`)"),
|
|
174
|
+
None => format!("task {id}"),
|
|
175
|
+
})
|
|
176
|
+
}
|
|
170
177
|
_ => None,
|
|
171
178
|
};
|
|
172
179
|
(name.to_string(), summary)
|
|
@@ -3013,12 +3020,15 @@ mod tui {
|
|
|
3013
3020
|
let system_prompt = crate::with_launch_context(
|
|
3014
3021
|
&crate::system_prompt_for_model(true),
|
|
3015
3022
|
);
|
|
3016
|
-
app.backend = Arc::new(
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3023
|
+
app.backend = Arc::new(
|
|
3024
|
+
OpenAiBackend::new(
|
|
3025
|
+
provider.base_url,
|
|
3026
|
+
provider.api_key,
|
|
3027
|
+
provider.model,
|
|
3028
|
+
Some(system_prompt),
|
|
3029
|
+
)
|
|
3030
|
+
.with_session_token(provider.session_token),
|
|
3031
|
+
);
|
|
3022
3032
|
app.current_model_name = provider.display_name.clone();
|
|
3023
3033
|
app.tool_calling = true;
|
|
3024
3034
|
// Selecting a cloud tier puts us in cloud mode.
|
|
@@ -4142,6 +4152,17 @@ mod tests {
|
|
|
4142
4152
|
);
|
|
4143
4153
|
}
|
|
4144
4154
|
|
|
4155
|
+
#[test]
|
|
4156
|
+
fn tool_title_task_tools_name_the_task() {
|
|
4157
|
+
for name in ["command_output", "monitor_command", "kill_command"] {
|
|
4158
|
+
assert_eq!(
|
|
4159
|
+
tool_title(name, r#"{"task_id":999999}"#),
|
|
4160
|
+
format!("{name} · task 999999")
|
|
4161
|
+
);
|
|
4162
|
+
}
|
|
4163
|
+
assert_eq!(tool_title("monitor_command", "{}"), "monitor_command");
|
|
4164
|
+
}
|
|
4165
|
+
|
|
4145
4166
|
#[test]
|
|
4146
4167
|
fn tool_title_file_tools_show_the_path() {
|
|
4147
4168
|
for name in [
|
|
@@ -349,12 +349,15 @@ pub async fn run(config: HeadlessConfig) -> i32 {
|
|
|
349
349
|
&crate::workspace::additional_roots(),
|
|
350
350
|
));
|
|
351
351
|
|
|
352
|
-
let backend: Arc<dyn InferenceBackend> = Arc::new(
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
352
|
+
let backend: Arc<dyn InferenceBackend> = Arc::new(
|
|
353
|
+
OpenAiBackend::new(
|
|
354
|
+
cfg.base_url,
|
|
355
|
+
cfg.api_key,
|
|
356
|
+
cfg.model.clone(),
|
|
357
|
+
Some(system_prompt),
|
|
358
|
+
)
|
|
359
|
+
.with_session_token(cfg.session_token),
|
|
360
|
+
);
|
|
358
361
|
|
|
359
362
|
if config.resume {
|
|
360
363
|
let Some(history) = session_store::load(&config.session_id) else {
|