Skip to content

Commit 0a86079

Browse files
committed
idk some stuff I guess
2 parents 076412d + 52b5455 commit 0a86079

File tree

40 files changed

+1659
-208
lines changed

40 files changed

+1659
-208
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ winnow = "0.6.2"
168168
# https://github.com/seanmonstar/reqwest/blob/v0.12.12/Cargo.toml
169169
rustls = "0.23.23"
170170
rustls-native-certs = "0.8.1"
171-
webpki-roots = "0.26.8"
171+
webpki-roots = "=0.26.8"
172172

173173

174174
[workspace.lints.rust]

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,14 @@ pnpm install --ignore-scripts
155155
### 3. Start Local Development
156156
To compile and view changes made to `q chat`:
157157
```shell
158-
cargo run --bin q_cli -- chat
158+
cargo run --bin chat_cli
159159
```
160160

161-
> If you are working on other q commands, just replace `chat` with the command name
161+
> If you are working on other q commands, just append `-- <command name>`. For example, to run `q login`, you can run `cargo run --bin chat_cli -- login`
162162
163163
To run tests for the Q CLI crate:
164164
```shell
165-
cargo test -p q_cli
165+
cargo test -p chat_cli
166166
```
167167

168168
To format Rust files:

build-scripts/manifest.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ def app_manifest():
6464
path="Contents/MacOS/qterm",
6565
identifier="com.amazon.qterm",
6666
),
67+
EmbeddedRequirement(
68+
path="Contents/MacOS/qchat",
69+
identifier="com.amazon.qchat",
70+
),
6771
],
6872
)
6973

crates/chat-cli/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ workspace = true
1414
default = []
1515
wayland = ["arboard/wayland-data-control"]
1616

17+
[[bin]]
18+
name = "test_mcp_server"
19+
path = "test_mcp_server/test_server.rs"
20+
test = true
21+
doc = false
22+
1723
[dependencies]
1824
amzn-codewhisperer-client = { path = "../amzn-codewhisperer-client" }
1925
amzn-codewhisperer-streaming-client = { path = "../amzn-codewhisperer-streaming-client" }
@@ -147,7 +153,7 @@ unicode-width = "0.2.0"
147153
url = "2.5.4"
148154
uuid = { version = "1.15.1", features = ["v4", "serde"] }
149155
walkdir = "2.5.0"
150-
webpki-roots = "0.26.8"
156+
webpki-roots = "=0.26.8"
151157
whoami = "1.6.0"
152158
winnow = "=0.6.2"
153159

crates/chat-cli/src/api_client/clients/streaming_client.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl StreamingClient {
6969
{
7070
Self::new_qdeveloper_client(database, &Endpoint::load_q()).await?
7171
} else {
72-
Self::new_codewhisperer_client(database, &Endpoint::load_codewhisperer()).await
72+
Self::new_codewhisperer_client(database, &Endpoint::load_codewhisperer(&database)).await
7373
},
7474
)
7575
}
@@ -261,7 +261,7 @@ mod tests {
261261
#[tokio::test]
262262
async fn create_clients() {
263263
let mut database = Database::new().await.unwrap();
264-
let endpoint = Endpoint::load_codewhisperer();
264+
let endpoint = Endpoint::load_codewhisperer(&database);
265265

266266
let _ = StreamingClient::new(&mut database).await;
267267
let _ = StreamingClient::new_codewhisperer_client(&mut database, &endpoint).await;
@@ -285,6 +285,7 @@ mod tests {
285285
.send_message(ConversationState {
286286
conversation_id: None,
287287
user_input_message: UserInputMessage {
288+
images: None,
288289
content: "Hello".into(),
289290
user_input_message_context: None,
290291
user_intent: None,
@@ -310,12 +311,14 @@ mod tests {
310311
.send_message(ConversationState {
311312
conversation_id: None,
312313
user_input_message: UserInputMessage {
314+
images: None,
313315
content: "How about rustc?".into(),
314316
user_input_message_context: None,
315317
user_intent: None,
316318
},
317319
history: Some(vec![
318320
ChatMessage::UserInputMessage(UserInputMessage {
321+
images: None,
319322
content: "What language is the linux kernel written in, and who wrote it?".into(),
320323
user_input_message_context: None,
321324
user_intent: None,

crates/chat-cli/src/api_client/model.rs

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use aws_smithy_types::Document;
1+
use aws_smithy_types::{
2+
Blob,
3+
Document,
4+
};
25
use serde::{
36
Deserialize,
47
Serialize,
@@ -565,17 +568,113 @@ impl From<GitState> for amzn_qdeveloper_streaming_client::types::GitState {
565568
}
566569
}
567570

571+
#[derive(Debug, Clone, Serialize, Deserialize)]
572+
pub struct ImageBlock {
573+
pub format: ImageFormat,
574+
pub source: ImageSource,
575+
}
576+
577+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
578+
pub enum ImageFormat {
579+
Gif,
580+
Jpeg,
581+
Png,
582+
Webp,
583+
}
584+
585+
impl std::str::FromStr for ImageFormat {
586+
type Err = String;
587+
588+
fn from_str(s: &str) -> Result<Self, Self::Err> {
589+
match s.trim().to_lowercase().as_str() {
590+
"gif" => Ok(ImageFormat::Gif),
591+
"jpeg" => Ok(ImageFormat::Jpeg),
592+
"jpg" => Ok(ImageFormat::Jpeg),
593+
"png" => Ok(ImageFormat::Png),
594+
"webp" => Ok(ImageFormat::Webp),
595+
_ => Err(format!("Failed to parse '{}' as ImageFormat", s)),
596+
}
597+
}
598+
}
599+
600+
impl From<ImageFormat> for amzn_codewhisperer_streaming_client::types::ImageFormat {
601+
fn from(value: ImageFormat) -> Self {
602+
match value {
603+
ImageFormat::Gif => Self::Gif,
604+
ImageFormat::Jpeg => Self::Jpeg,
605+
ImageFormat::Png => Self::Png,
606+
ImageFormat::Webp => Self::Webp,
607+
}
608+
}
609+
}
610+
impl From<ImageFormat> for amzn_qdeveloper_streaming_client::types::ImageFormat {
611+
fn from(value: ImageFormat) -> Self {
612+
match value {
613+
ImageFormat::Gif => Self::Gif,
614+
ImageFormat::Jpeg => Self::Jpeg,
615+
ImageFormat::Png => Self::Png,
616+
ImageFormat::Webp => Self::Webp,
617+
}
618+
}
619+
}
620+
621+
#[non_exhaustive]
622+
#[derive(Debug, Clone, Serialize, Deserialize)]
623+
pub enum ImageSource {
624+
Bytes(Vec<u8>),
625+
#[non_exhaustive]
626+
Unknown,
627+
}
628+
629+
impl From<ImageSource> for amzn_codewhisperer_streaming_client::types::ImageSource {
630+
fn from(value: ImageSource) -> Self {
631+
match value {
632+
ImageSource::Bytes(bytes) => Self::Bytes(Blob::new(bytes)),
633+
ImageSource::Unknown => Self::Unknown,
634+
}
635+
}
636+
}
637+
impl From<ImageSource> for amzn_qdeveloper_streaming_client::types::ImageSource {
638+
fn from(value: ImageSource) -> Self {
639+
match value {
640+
ImageSource::Bytes(bytes) => Self::Bytes(Blob::new(bytes)),
641+
ImageSource::Unknown => Self::Unknown,
642+
}
643+
}
644+
}
645+
646+
impl From<ImageBlock> for amzn_codewhisperer_streaming_client::types::ImageBlock {
647+
fn from(value: ImageBlock) -> Self {
648+
Self::builder()
649+
.format(value.format.into())
650+
.source(value.source.into())
651+
.build()
652+
.expect("Failed to build ImageBlock")
653+
}
654+
}
655+
impl From<ImageBlock> for amzn_qdeveloper_streaming_client::types::ImageBlock {
656+
fn from(value: ImageBlock) -> Self {
657+
Self::builder()
658+
.format(value.format.into())
659+
.source(value.source.into())
660+
.build()
661+
.expect("Failed to build ImageBlock")
662+
}
663+
}
664+
568665
#[derive(Debug, Clone)]
569666
pub struct UserInputMessage {
570667
pub content: String,
571668
pub user_input_message_context: Option<UserInputMessageContext>,
572669
pub user_intent: Option<UserIntent>,
670+
pub images: Option<Vec<ImageBlock>>,
573671
}
574672

575673
impl From<UserInputMessage> for amzn_codewhisperer_streaming_client::types::UserInputMessage {
576674
fn from(value: UserInputMessage) -> Self {
577675
Self::builder()
578676
.content(value.content)
677+
.set_images(value.images.map(|images| images.into_iter().map(Into::into).collect()))
579678
.set_user_input_message_context(value.user_input_message_context.map(Into::into))
580679
.set_user_intent(value.user_intent.map(Into::into))
581680
.origin(amzn_codewhisperer_streaming_client::types::Origin::Cli)
@@ -588,6 +687,7 @@ impl From<UserInputMessage> for amzn_qdeveloper_streaming_client::types::UserInp
588687
fn from(value: UserInputMessage) -> Self {
589688
Self::builder()
590689
.content(value.content)
690+
.set_images(value.images.map(|images| images.into_iter().map(Into::into).collect()))
591691
.set_user_input_message_context(value.user_input_message_context.map(Into::into))
592692
.set_user_intent(value.user_intent.map(Into::into))
593693
.origin(amzn_qdeveloper_streaming_client::types::Origin::Cli)
@@ -654,6 +754,10 @@ mod tests {
654754
#[test]
655755
fn build_user_input_message() {
656756
let user_input_message = UserInputMessage {
757+
images: Some(vec![ImageBlock {
758+
format: ImageFormat::Png,
759+
source: ImageSource::Bytes(vec![1, 2, 3]),
760+
}]),
657761
content: "test content".to_string(),
658762
user_input_message_context: Some(UserInputMessageContext {
659763
env_state: Some(EnvState {
@@ -690,6 +794,7 @@ mod tests {
690794
assert_eq!(format!("{codewhisper_input:?}"), format!("{qdeveloper_input:?}"));
691795

692796
let minimal_message = UserInputMessage {
797+
images: None,
693798
content: "test content".to_string(),
694799
user_input_message_context: None,
695800
user_intent: None,

crates/chat-cli/src/auth/builder_id.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ impl std::fmt::Display for OAuthFlow {
7070
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7171
match *self {
7272
OAuthFlow::DeviceCode => write!(f, "DeviceCode"),
73-
OAuthFlow::Pkce => write!(f, "PKCE"),
73+
OAuthFlow::Pkce => write!(f, "Pkce"),
7474
}
7575
}
7676
}
@@ -594,7 +594,7 @@ mod tests {
594594
#[test]
595595
fn test_oauth_flow_ser_deser() {
596596
test_ser_deser!(OAuthFlow, OAuthFlow::DeviceCode, "DeviceCode");
597-
test_ser_deser!(OAuthFlow, OAuthFlow::Pkce, "PKCE");
597+
test_ser_deser!(OAuthFlow, OAuthFlow::Pkce, "Pkce");
598598
}
599599

600600
#[test]

crates/chat-cli/src/cli/chat/command.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -810,13 +810,8 @@ impl Command {
810810
}
811811
},
812812
"usage" => Self::Usage,
813-
unknown_command => {
814-
// If the command starts with a slash but isn't recognized,
815-
// return an error instead of treating it as a prompt
816-
return Err(format!(
817-
"Unknown command: '/{}'. Type '/help' to see available commands.\nTo use a literal slash at the beginning of your message, escape it with a backslash (e.g., '\\//hey' for '/hey').",
818-
unknown_command
819-
));
813+
_unknown_command => Self::Ask {
814+
prompt: input.to_string(),
820815
},
821816
});
822817
}

crates/chat-cli/src/cli/chat/consts.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,13 @@ pub const MAX_USER_MESSAGE_SIZE: usize = 600_000;
1616
/// In tokens
1717
pub const CONTEXT_WINDOW_SIZE: usize = 200_000;
1818

19+
pub const CONTEXT_FILES_MAX_SIZE: usize = 150_000;
20+
1921
pub const MAX_CHARS: usize = TokenCounter::token_to_chars(CONTEXT_WINDOW_SIZE); // Character-based warning threshold
22+
23+
pub const DUMMY_TOOL_NAME: &str = "dummy";
24+
25+
pub const MAX_NUMBER_OF_IMAGES_PER_REQUEST: usize = 10;
26+
27+
/// In bytes - 10 MB
28+
pub const MAX_IMAGE_SIZE: usize = 10 * 1024 * 1024;

0 commit comments

Comments
 (0)