Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/jp_cli/src/cmd/attachment/rm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl IntoPartialAppConfig for Rm {
.collect::<Result<Vec<_>, _>>()?;

for attachment in partial.conversation.attachments {
let url = AttachmentConfig::from_partial(attachment.clone())?.to_url()?;
let url = AttachmentConfig::from_partial(attachment.clone(), vec![])?.to_url()?;
if !to_remove_attachments.contains(&url) {
attachments.push(attachment);
}
Expand Down
16 changes: 2 additions & 14 deletions crates/jp_cli/src/cmd/conversation/fork.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,7 @@ mod tests {
use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};

use assert_matches::assert_matches;
use jp_config::{
AppConfig, Config as _, PartialAppConfig,
conversation::tool::RunMode,
model::id::{PartialModelIdConfig, ProviderId},
};
use jp_config::AppConfig;
use jp_conversation::{
Conversation, ConversationEvent, ConversationStream,
event::{ChatRequest, ChatResponse},
Expand Down Expand Up @@ -406,15 +402,7 @@ mod tests {
for (name, case) in cases {
let tmp = tempdir().unwrap();

let mut partial = PartialAppConfig::empty();
partial.conversation.tools.defaults.run = Some(RunMode::Ask);
partial.assistant.model.id = PartialModelIdConfig {
provider: Some(ProviderId::Anthropic),
name: Some("test".parse().unwrap()),
}
.into();

let config = AppConfig::from_partial(partial).unwrap();
let config = AppConfig::new_test();
let workspace = Workspace::new(tmp.path());
let mut ctx = Ctx::new(
workspace,
Expand Down
2 changes: 1 addition & 1 deletion crates/jp_config/src/conversation/attachment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl FromStr for AttachmentConfig {

fn from_str(s: &str) -> Result<Self, Self::Err> {
let partial = PartialAttachmentConfig::from_str(s)?;
Self::from_partial(partial).map_err(Into::into)
Self::from_partial(partial, vec![]).map_err(Into::into)
}
}

Expand Down
4 changes: 2 additions & 2 deletions crates/jp_config/src/conversation/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,7 @@ mod tests {
))
);

let cfg = CommandConfigOrString::from_partial(p.command.clone().unwrap()).unwrap();
let cfg = CommandConfigOrString::from_partial(p.command.clone().unwrap(), vec![]).unwrap();
assert_eq!(cfg.command(), ToolCommandConfig {
program: "cargo".to_owned(),
args: vec!["check".to_owned()],
Expand All @@ -1073,7 +1073,7 @@ mod tests {
))
);

let cfg = CommandConfigOrString::from_partial(p.command.unwrap()).unwrap();
let cfg = CommandConfigOrString::from_partial(p.command.unwrap(), vec![]).unwrap();
assert_eq!(cfg.command(), ToolCommandConfig {
program: "cargo".to_owned(),
args: vec!["check".to_owned(), "--verbose".to_owned()],
Expand Down
25 changes: 25 additions & 0 deletions crates/jp_config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,31 @@ impl ToPartial for AppConfig {
}

impl AppConfig {
/// Return a default configuration for testing purposes.
///
/// This CANNOT be used in release mode.
#[cfg(debug_assertions)]
#[doc(hidden)]
#[must_use]
pub fn new_test() -> Self {
use crate::{
conversation::tool::RunMode,
model::id::{Name, PartialModelIdConfig, ProviderId},
};

let mut partial = PartialAppConfig::empty();

partial.conversation.title.generate.auto = Some(false);
partial.conversation.tools.defaults.run = Some(RunMode::Ask);
partial.assistant.model.id = PartialModelIdConfig {
provider: Some(ProviderId::Anthropic),
name: Some(Name("test".to_owned())),
}
.into();

Self::from_partial(partial, vec![]).expect("valid config")
}

/// Return a list of all fields in the configuration.
///
/// The fields are returned in alphabetical order, with nested fields
Expand Down
2 changes: 1 addition & 1 deletion crates/jp_config/src/model/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ impl FromStr for ReasoningConfig {

fn from_str(s: &str) -> Result<Self, Self::Err> {
let partial = PartialReasoningConfig::from_str(s)?;
Self::from_partial(partial).map_err(Into::into)
Self::from_partial(partial, vec![]).map_err(Into::into)
}
}

Expand Down
8 changes: 4 additions & 4 deletions crates/jp_config/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ pub fn build(mut partial: PartialAppConfig) -> Result<AppConfig, Error> {
"Configuration details."
);

let mut config: AppConfig = Config::from_partial(partial)?;
let mut config: AppConfig = Config::from_partial(partial, vec![])?;

// Sort instructions by position.
config
Expand Down Expand Up @@ -510,7 +510,7 @@ mod tests {
let error = build(PartialAppConfig::default_values(&()).unwrap().unwrap()).unwrap_err();
assert_matches!(
error,
Error::Schematic(schematic::ConfigError::MissingRequired(_))
Error::Schematic(schematic::ConfigError::MissingRequired { .. })
);

let mut partial = PartialAppConfig::default_values(&()).unwrap().unwrap();
Expand All @@ -536,15 +536,15 @@ mod tests {
let mut partial = PartialAppConfig::default_values(&()).unwrap().unwrap();

let error = build(partial.clone()).unwrap_err();
assert_matches!(error, Error::Schematic(MissingRequired(v)) if v == "provider");
assert_matches!(error, Error::Schematic(MissingRequired { fields }) if fields == vec!["assistant", "model", "id", "provider"]);
partial.assistant.model.id = PartialModelIdConfig {
provider: Some(ProviderId::Openrouter),
name: Some("foo".parse().unwrap()),
}
.into();

let error = build(partial.clone()).unwrap_err();
assert_matches!(error, Error::Schematic(MissingRequired(v)) if v == "run");
assert_matches!(error, Error::Schematic(MissingRequired{ fields }) if fields == vec!["conversation", "tools", "defaults", "run"]);
partial.conversation.tools.defaults.run = Some(RunMode::Unattended);

build(partial).unwrap();
Expand Down
41 changes: 20 additions & 21 deletions crates/jp_conversation/src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ impl ConversationStream {
partial.merge(&(), delta.into())?;
}

AppConfig::from_partial(partial).map_err(Into::into)
AppConfig::from_partial(partial, vec![]).map_err(Into::into)
}

/// Removes all events from the end of the stream, until a [`ChatRequest`]
Expand Down Expand Up @@ -470,6 +470,22 @@ impl ConversationStream {
front_config: self.base_config.to_partial(),
}
}

/// Return a default conversation stream for testing purposes.
///
/// This CANNOT be used in release mode.
#[cfg(debug_assertions)]
#[doc(hidden)]
#[must_use]
pub fn new_test() -> Self {
use time::macros::utc_datetime;

Self {
base_config: AppConfig::new_test().into(),
events: vec![],
created_at: utc_datetime!(2020-01-01 0:00),
}
}
}

impl Extend<ConversationEventWithConfig> for ConversationStream {
Expand Down Expand Up @@ -748,7 +764,7 @@ impl FromIterator<ConversationEventWithConfig> for Result<ConversationStream, St
return Err(StreamError::FromEmptyIterator);
};

let mut stream = ConversationStream::new(AppConfig::from_partial(config)?.into());
let mut stream = ConversationStream::new(AppConfig::from_partial(config, vec![])?.into());
stream.push(first_event);
stream.extend(events);

Expand Down Expand Up @@ -829,7 +845,7 @@ impl<'de> Deserialize<'de> for ConversationStream {
match events.remove(0) {
InternalEvent::ConfigDelta(base_config) => Ok(Self {
created_at: base_config.timestamp,
base_config: AppConfig::from_partial(base_config.into())
base_config: AppConfig::from_partial(base_config.into(), vec![])
.map_err(Error::custom)?
.into(),
events,
Expand Down Expand Up @@ -988,30 +1004,13 @@ impl<'de> Deserialize<'de> for InternalEvent {

#[cfg(test)]
mod tests {
use jp_config::{
conversation::tool::RunMode,
model::id::{PartialModelIdConfig, ProviderId},
};
use time::macros::utc_datetime;

use super::*;

#[test]
fn test_conversation_stream_serialization_roundtrip() {
let mut base_config = PartialAppConfig::empty();
base_config.conversation.title.generate.auto = Some(false);
base_config.conversation.tools.defaults.run = Some(RunMode::Ask);
base_config.assistant.model.id = PartialModelIdConfig {
provider: Some(ProviderId::Anthropic),
name: Some("test".parse().unwrap()),
}
.into();

let mut stream = ConversationStream {
base_config: AppConfig::from_partial(base_config).unwrap().into(),
events: vec![],
created_at: utc_datetime!(2020-01-01 0:00),
};
let mut stream = ConversationStream::new_test();

insta::assert_json_snapshot!(&stream);

Expand Down
4 changes: 2 additions & 2 deletions crates/jp_llm/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ impl TestRequest {
}
.into();

AppConfig::from_partial(cfg).unwrap().into()
AppConfig::from_partial(cfg, vec![]).unwrap().into()
})
.with_created_at(utc_datetime!(2020-01-01 0:00)),
)
Expand Down Expand Up @@ -128,7 +128,7 @@ impl TestRequest {
}
.into();

AppConfig::from_partial(cfg).unwrap().into()
AppConfig::from_partial(cfg, vec![]).unwrap().into()
})
.with_created_at(datetime!(2020-01-01 0:00 utc)),
)
Expand Down
32 changes: 4 additions & 28 deletions crates/jp_workspace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,11 +627,6 @@ pub fn user_data_dir() -> Result<PathBuf> {
mod tests {
use std::{collections::HashMap, fs, time::Duration};

use jp_config::{
Config as _, PartialAppConfig,
conversation::tool::RunMode,
model::id::{PartialModelIdConfig, ProviderId},
};
use jp_storage::{CONVERSATIONS_DIR, METADATA_FILE, value::read_json};
use tempfile::tempdir;
use test_log::test;
Expand Down Expand Up @@ -738,19 +733,9 @@ mod tests {
let storage = root.join("storage");

let mut workspace = Workspace::new(&root);
let config = AppConfig::new_test();

let mut partial = PartialAppConfig::empty();
partial.conversation.tools.defaults.run = Some(RunMode::Ask);
partial.assistant.model.id = PartialModelIdConfig {
provider: Some(ProviderId::Anthropic),
name: Some("test".parse().unwrap()),
}
.into();

let id = workspace.create_conversation(
Conversation::default(),
AppConfig::from_partial(partial).unwrap().into(),
);
let id = workspace.create_conversation(Conversation::default(), config.into());
workspace
.set_active_conversation_id(id, UtcDateTime::UNIX_EPOCH)
.unwrap();
Expand Down Expand Up @@ -818,18 +803,9 @@ mod tests {
assert!(workspace.state.local.conversations.is_empty());

let conversation = Conversation::default();
let mut partial = PartialAppConfig::empty();
partial.conversation.tools.defaults.run = Some(RunMode::Ask);
partial.assistant.model.id = PartialModelIdConfig {
provider: Some(ProviderId::Anthropic),
name: Some("test".parse().unwrap()),
}
.into();
let config = AppConfig::new_test();
let id = workspace.create_conversation(conversation.clone(), config.into());

let id = workspace.create_conversation(
conversation.clone(),
AppConfig::from_partial(partial).unwrap().into(),
);
assert_eq!(
workspace
.state
Expand Down
Loading