Skip to content

Commit 076412d

Browse files
committed
start telemetry, state, and settings refactor
1 parent a474cd2 commit 076412d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1702
-2517
lines changed

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

Lines changed: 34 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use tracing::error;
88

99
use super::shared::bearer_sdk_config;
1010
use crate::api_client::interceptor::opt_out::OptOutInterceptor;
11-
use crate::api_client::profile::Profile;
1211
use crate::api_client::{
1312
ApiClientError,
1413
Endpoint,
@@ -18,6 +17,11 @@ use crate::aws_common::{
1817
UserAgentOverrideInterceptor,
1918
app_name,
2019
};
20+
use crate::database::Database;
21+
use crate::database::state::{
22+
AuthProfile,
23+
StateDatabase,
24+
};
2125

2226
mod inner {
2327
use amzn_codewhisperer_client::Client as CodewhispererClient;
@@ -32,27 +36,24 @@ mod inner {
3236
#[derive(Clone, Debug)]
3337
pub struct Client {
3438
inner: inner::Inner,
35-
profile_arn: Option<String>,
39+
profile: Option<AuthProfile>,
3640
}
3741

3842
impl Client {
39-
pub async fn new() -> Result<Client, ApiClientError> {
43+
pub async fn new(database: &mut Database, endpoint: Option<Endpoint>) -> Client {
4044
if cfg!(test) {
41-
return Ok(Self {
45+
return Self {
4246
inner: inner::Inner::Mock,
43-
profile_arn: None,
44-
});
47+
profile: None,
48+
};
4549
}
4650

47-
let endpoint = Endpoint::load_codewhisperer();
48-
Ok(Self::new_codewhisperer_client(&endpoint).await)
49-
}
50-
51-
pub async fn new_codewhisperer_client(endpoint: &Endpoint) -> Self {
52-
let conf_builder: amzn_codewhisperer_client::config::Builder = (&bearer_sdk_config(endpoint).await).into();
51+
let endpoint = endpoint.unwrap_or(Endpoint::load_codewhisperer(database));
52+
let conf_builder: amzn_codewhisperer_client::config::Builder =
53+
(&bearer_sdk_config(database, &endpoint).await).into();
5354
let conf = conf_builder
54-
.http_client(crate::aws_common::http_client::client())
55-
.interceptor(OptOutInterceptor::new())
55+
.http_client(crate::aws_common::http_client::client(database))
56+
.interceptor(OptOutInterceptor::new(database))
5657
.interceptor(UserAgentOverrideInterceptor::new())
5758
.bearer_token_resolver(BearerResolver)
5859
.app_name(app_name())
@@ -61,47 +62,34 @@ impl Client {
6162

6263
let inner = inner::Inner::Codewhisperer(CodewhispererClient::from_conf(conf));
6364

64-
let profile_arn = match crate::settings::state::get_value("api.codewhisperer.profile") {
65-
Ok(Some(profile)) => match profile.get("arn") {
66-
Some(arn) => match arn.as_str() {
67-
Some(arn) => Some(arn.to_string()),
68-
None => {
69-
error!("Stored arn is not a string. Instead it was: {arn}");
70-
None
71-
},
72-
},
73-
None => {
74-
error!("Stored profile does not contain an arn. Instead it was: {profile}");
75-
None
76-
},
77-
},
78-
Ok(None) => None,
65+
let profile = match database.get_auth_profile() {
66+
Ok(profile) => profile,
7967
Err(err) => {
80-
error!("Failed to retrieve profile: {}", err);
68+
error!("Failed to get auth profile: {err}");
8169
None
8270
},
8371
};
8472

85-
Self { inner, profile_arn }
73+
Self { inner, profile }
8674
}
8775

88-
// .telemetry_event(TelemetryEvent::UserTriggerDecisionEvent(user_trigger_decision_event))
89-
// .user_context(user_context)
90-
// .opt_out_preference(opt_out_preference)
9176
pub async fn send_telemetry_event(
9277
&self,
9378
telemetry_event: TelemetryEvent,
9479
user_context: UserContext,
95-
opt_out: OptOutPreference,
80+
telemetry_enabled: bool,
9681
) -> Result<(), ApiClientError> {
9782
match &self.inner {
9883
inner::Inner::Codewhisperer(client) => {
9984
let _ = client
10085
.send_telemetry_event()
10186
.telemetry_event(telemetry_event)
10287
.user_context(user_context)
103-
.opt_out_preference(opt_out)
104-
.set_profile_arn(self.profile_arn.clone())
88+
.opt_out_preference(match telemetry_enabled {
89+
true => OptOutPreference::OptIn,
90+
false => OptOutPreference::OptOut,
91+
})
92+
.set_profile_arn(self.profile.as_ref().map(|p| p.arn.clone()))
10593
.send()
10694
.await;
10795
Ok(())
@@ -110,23 +98,23 @@ impl Client {
11098
}
11199
}
112100

113-
pub async fn list_available_profiles(&self) -> Result<Vec<Profile>, ApiClientError> {
101+
pub async fn list_available_profiles(&self) -> Result<Vec<AuthProfile>, ApiClientError> {
114102
match &self.inner {
115103
inner::Inner::Codewhisperer(client) => {
116104
let mut profiles = vec![];
117105
let mut client = client.list_available_profiles().into_paginator().send();
118106
while let Some(profiles_output) = client.next().await {
119-
profiles.extend(profiles_output?.profiles().iter().cloned().map(Profile::from));
107+
profiles.extend(profiles_output?.profiles().iter().cloned().map(AuthProfile::from));
120108
}
121109

122110
Ok(profiles)
123111
},
124112
inner::Inner::Mock => Ok(vec![
125-
Profile {
113+
AuthProfile {
126114
arn: "my:arn:1".to_owned(),
127115
profile_name: "MyProfile".to_owned(),
128116
},
129-
Profile {
117+
AuthProfile {
130118
arn: "my:arn:2".to_owned(),
131119
profile_name: "MyOtherProfile".to_owned(),
132120
},
@@ -147,15 +135,14 @@ mod tests {
147135

148136
#[tokio::test]
149137
async fn create_clients() {
150-
let endpoint = Endpoint::load_codewhisperer();
151-
152-
let _ = Client::new().await;
153-
let _ = Client::new_codewhisperer_client(&endpoint).await;
138+
let mut database = crate::database::Database::new().await.unwrap();
139+
let _ = Client::new(&mut database, None).await;
154140
}
155141

156142
#[tokio::test]
157143
async fn test_mock() {
158-
let client = Client::new().await.unwrap();
144+
let mut database = crate::database::Database::new().await.unwrap();
145+
let client = Client::new(&mut database, None).await;
159146
client
160147
.send_telemetry_event(
161148
TelemetryEvent::ChatAddMessageEvent(
@@ -171,7 +158,7 @@ mod tests {
171158
.product("<product>")
172159
.build()
173160
.unwrap(),
174-
OptOutPreference::OptIn,
161+
false,
175162
)
176163
.await
177164
.unwrap();

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

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,16 @@ use crate::api_client::{
1414
Endpoint,
1515
};
1616
use crate::aws_common::behavior_version;
17+
use crate::database::Database;
18+
use crate::database::settings::Setting;
1719

1820
// TODO(bskiser): confirm timeout is updated to an appropriate value?
1921
const DEFAULT_TIMEOUT_DURATION: Duration = Duration::from_secs(60 * 5);
2022

21-
pub(crate) fn timeout_config() -> TimeoutConfig {
22-
let timeout = crate::settings::settings::get_int("api.timeout")
23-
.ok()
24-
.flatten()
23+
pub fn timeout_config(database: &Database) -> TimeoutConfig {
24+
let timeout = database
25+
.settings
26+
.get_int(Setting::ApiTimeout)
2527
.and_then(|i| i.try_into().ok())
2628
.map_or(DEFAULT_TIMEOUT_DURATION, Duration::from_millis);
2729

@@ -39,27 +41,31 @@ pub(crate) fn stalled_stream_protection_config() -> StalledStreamProtectionConfi
3941
.build()
4042
}
4143

42-
async fn base_sdk_config(region: Region, credentials_provider: impl ProvideCredentials + 'static) -> SdkConfig {
44+
async fn base_sdk_config(
45+
database: &Database,
46+
region: Region,
47+
credentials_provider: impl ProvideCredentials + 'static,
48+
) -> SdkConfig {
4349
aws_config::defaults(behavior_version())
4450
.region(region)
4551
.credentials_provider(credentials_provider)
46-
.timeout_config(timeout_config())
52+
.timeout_config(timeout_config(database))
4753
.retry_config(RetryConfig::adaptive())
4854
.load()
4955
.await
5056
}
5157

52-
pub(crate) async fn bearer_sdk_config(endpoint: &Endpoint) -> SdkConfig {
58+
pub async fn bearer_sdk_config(database: &Database, endpoint: &Endpoint) -> SdkConfig {
5359
let credentials = Credentials::new("xxx", "xxx", None, None, "xxx");
54-
base_sdk_config(endpoint.region().clone(), credentials).await
60+
base_sdk_config(database, endpoint.region().clone(), credentials).await
5561
}
5662

57-
pub(crate) async fn sigv4_sdk_config(endpoint: &Endpoint) -> Result<SdkConfig, ApiClientError> {
63+
pub async fn sigv4_sdk_config(database: &Database, endpoint: &Endpoint) -> Result<SdkConfig, ApiClientError> {
5864
let credentials_chain = CredentialsChain::new().await;
5965

6066
if let Err(err) = credentials_chain.provide_credentials().await {
6167
return Err(ApiClientError::Credentials(err));
6268
};
6369

64-
Ok(base_sdk_config(endpoint.region().clone(), credentials_chain).await)
70+
Ok(base_sdk_config(database, endpoint.region().clone(), credentials_chain).await)
6571
}

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

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ use crate::aws_common::{
3030
UserAgentOverrideInterceptor,
3131
app_name,
3232
};
33+
use crate::database::Database;
34+
use crate::database::state::{
35+
AuthProfile,
36+
StateDatabase,
37+
};
3338

3439
mod inner {
3540
use std::sync::{
@@ -53,34 +58,35 @@ mod inner {
5358
#[derive(Clone, Debug)]
5459
pub struct StreamingClient {
5560
inner: inner::Inner,
56-
profile_arn: Option<String>,
61+
profile: Option<AuthProfile>,
5762
}
5863

5964
impl StreamingClient {
60-
pub async fn new() -> Result<Self, ApiClientError> {
61-
let client = if crate::util::system_info::in_cloudshell()
62-
|| std::env::var("Q_USE_SENDMESSAGE").is_ok_and(|v| !v.is_empty())
63-
{
64-
Self::new_qdeveloper_client(&Endpoint::load_q()).await?
65-
} else {
66-
Self::new_codewhisperer_client(&Endpoint::load_codewhisperer()).await
67-
};
68-
Ok(client)
65+
pub async fn new(database: &mut Database) -> Result<Self, ApiClientError> {
66+
Ok(
67+
if crate::util::system_info::in_cloudshell()
68+
|| std::env::var("Q_USE_SENDMESSAGE").is_ok_and(|v| !v.is_empty())
69+
{
70+
Self::new_qdeveloper_client(database, &Endpoint::load_q()).await?
71+
} else {
72+
Self::new_codewhisperer_client(database, &Endpoint::load_codewhisperer()).await
73+
},
74+
)
6975
}
7076

7177
pub fn mock(events: Vec<Vec<ChatResponseStream>>) -> Self {
7278
Self {
7379
inner: inner::Inner::Mock(Arc::new(Mutex::new(events.into_iter()))),
74-
profile_arn: None,
80+
profile: None,
7581
}
7682
}
7783

78-
pub async fn new_codewhisperer_client(endpoint: &Endpoint) -> Self {
84+
pub async fn new_codewhisperer_client(database: &mut Database, endpoint: &Endpoint) -> Self {
7985
let conf_builder: amzn_codewhisperer_streaming_client::config::Builder =
80-
(&bearer_sdk_config(endpoint).await).into();
86+
(&bearer_sdk_config(database, endpoint).await).into();
8187
let conf = conf_builder
82-
.http_client(crate::aws_common::http_client::client())
83-
.interceptor(OptOutInterceptor::new())
88+
.http_client(crate::aws_common::http_client::client(database))
89+
.interceptor(OptOutInterceptor::new(database))
8490
.interceptor(UserAgentOverrideInterceptor::new())
8591
.bearer_token_resolver(BearerResolver)
8692
.app_name(app_name())
@@ -89,36 +95,23 @@ impl StreamingClient {
8995
.build();
9096
let inner = inner::Inner::Codewhisperer(CodewhispererStreamingClient::from_conf(conf));
9197

92-
let profile_arn = match crate::settings::state::get_value("api.codewhisperer.profile") {
93-
Ok(Some(profile)) => match profile.get("arn") {
94-
Some(arn) => match arn.as_str() {
95-
Some(arn) => Some(arn.to_string()),
96-
None => {
97-
error!("Stored arn is not a string. Instead it was: {arn}");
98-
None
99-
},
100-
},
101-
None => {
102-
error!("Stored profile does not contain an arn. Instead it was: {profile}");
103-
None
104-
},
105-
},
106-
Ok(None) => None,
98+
let profile = match database.get_auth_profile() {
99+
Ok(profile) => profile,
107100
Err(err) => {
108-
error!("Failed to retrieve profile: {}", err);
101+
error!("Failed to get auth profile: {err}");
109102
None
110103
},
111104
};
112105

113-
Self { inner, profile_arn }
106+
Self { inner, profile }
114107
}
115108

116-
pub async fn new_qdeveloper_client(endpoint: &Endpoint) -> Result<Self, ApiClientError> {
109+
pub async fn new_qdeveloper_client(database: &Database, endpoint: &Endpoint) -> Result<Self, ApiClientError> {
117110
let conf_builder: amzn_qdeveloper_streaming_client::config::Builder =
118-
(&sigv4_sdk_config(endpoint).await?).into();
111+
(&sigv4_sdk_config(database, endpoint).await?).into();
119112
let conf = conf_builder
120-
.http_client(crate::aws_common::http_client::client())
121-
.interceptor(OptOutInterceptor::new())
113+
.http_client(crate::aws_common::http_client::client(database))
114+
.interceptor(OptOutInterceptor::new(database))
122115
.interceptor(UserAgentOverrideInterceptor::new())
123116
.app_name(app_name())
124117
.endpoint_url(endpoint.url())
@@ -127,7 +120,7 @@ impl StreamingClient {
127120
let client = QDeveloperStreamingClient::from_conf(conf);
128121
Ok(Self {
129122
inner: inner::Inner::QDeveloper(client),
130-
profile_arn: None,
123+
profile: None,
131124
})
132125
}
133126

@@ -162,7 +155,7 @@ impl StreamingClient {
162155
let response = client
163156
.generate_assistant_response()
164157
.conversation_state(conversation_state)
165-
.set_profile_arn(self.profile_arn.clone())
158+
.set_profile_arn(self.profile.as_ref().map(|p| p.arn.clone()))
166159
.send()
167160
.await;
168161

@@ -267,11 +260,12 @@ mod tests {
267260

268261
#[tokio::test]
269262
async fn create_clients() {
263+
let mut database = Database::new().await.unwrap();
270264
let endpoint = Endpoint::load_codewhisperer();
271265

272-
let _ = StreamingClient::new().await;
273-
let _ = StreamingClient::new_codewhisperer_client(&endpoint).await;
274-
let _ = StreamingClient::new_qdeveloper_client(&endpoint).await;
266+
let _ = StreamingClient::new(&mut database).await;
267+
let _ = StreamingClient::new_codewhisperer_client(&mut database, &endpoint).await;
268+
let _ = StreamingClient::new_qdeveloper_client(&mut database, &endpoint).await;
275269
}
276270

277271
#[tokio::test]
@@ -310,7 +304,8 @@ mod tests {
310304
#[ignore]
311305
#[tokio::test]
312306
async fn assistant_response() {
313-
let client = StreamingClient::new().await.unwrap();
307+
let mut database = Database::new().await.unwrap();
308+
let client = StreamingClient::new(&mut database).await.unwrap();
314309
let mut response = client
315310
.send_message(ConversationState {
316311
conversation_id: None,

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,4 @@ pub const PROD_CODEWHISPERER_FRA_ENDPOINT_URL: &str = "https://q.eu-central-1.am
1212
pub const PROD_CODEWHISPERER_FRA_ENDPOINT_REGION: Region = Region::from_static("eu-central-1");
1313

1414
// Opt out constants
15-
pub const SHARE_CODEWHISPERER_CONTENT_SETTINGS_KEY: &str = "codeWhisperer.shareCodeWhispererContentWithAWS";
1615
pub const X_AMZN_CODEWHISPERER_OPT_OUT_HEADER: &str = "x-amzn-codewhisperer-optout";

0 commit comments

Comments
 (0)