Skip to content

Commit

Permalink
Implement service queries for chat completions (#1)
Browse files Browse the repository at this point in the history
* Add a `chat_log` field to the state

Prepare to keep a chat transcript on chain.

* Add an operation to log a chat interaction

Update the on-chain chat transcript with the new interaction.

* Test logging some chat interactions

Ensure that they are stored in the state on chain.

* Change the service to handle GraphQL requests

For now no requests are actually handled.

* Add a `runtime` field to the `ApplicationService`

Prepare to perform HTTP queries.

* Add a mutation to perform a chat interaction

Creates an operation to log a chat interaction, but for now the response
is empty.

* Implement querying of chat completion API

Send an HTTP request to the Atoma network to retrieve a chat completion.

* Create a `ChatInteractionResponse` type

A helper type to parse the `ChatCompletionResponse` and later build a
`ChatInteraction`.

* Fetch chat completion to log to chat transcript

Include a real response from the Atoma network in the operation to log a
chat interaction.

* Test if `chat` mutation performs HTTP request

Ensure that a `chat` mutation leads to the service sending an HTTP
request to the Atoma proxy, and returning an operation to log the chat
interaction.

* Downgrade Rust version to workaround Wasm issue

Use a version known to be able to run Wasm contracts.

* Add an integration test for the API query

Ensure that the API queries from the service work correctly.
  • Loading branch information
jvff authored Feb 6, 2025
1 parent aea7c59 commit 7ff0843
Show file tree
Hide file tree
Showing 10 changed files with 544 additions and 35 deletions.
149 changes: 132 additions & 17 deletions Cargo.lock

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

13 changes: 13 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,27 @@ name = "atoma-demo"
version = "0.1.0"
edition = "2021"

[features]
test = ["proptest", "test-strategy"]

[dependencies]
async-graphql = { version = "=7.0.2", default-features = false }
async-graphql-derive = { version = "=7.0.2", default-features = false }
linera-sdk = { git = "https://github.com/jvff/linera-protocol", rev = "26a5299" }
proptest = { version = "1.6.0", optional = true }
serde = { version = "1.0.217", features = ["derive"] }
serde_json = "1.0.137"
test-strategy = { version = "0.4.0", optional = true }

[dev-dependencies]
atoma-demo = { path = ".", features = ["test"] }
linera-sdk = { git = "https://github.com/jvff/linera-protocol", rev = "26a5299", features = ["test"] }

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
linera-sdk = { git = "https://github.com/jvff/linera-protocol", rev = "26a5299", features = ["test", "wasmer", "unstable-oracles"] }
tokio = "1.39.3"
test-log = "*"

[[bin]]
name = "atoma_demo_contract"
path = "src/contract.rs"
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[toolchain]
channel = "1.84.0"
channel = "1.81.0"
components = [ "clippy", "rustfmt", "rust-src" ]
targets = [ "wasm32-unknown-unknown" ]
profile = "minimal"
18 changes: 17 additions & 1 deletion src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
#![cfg_attr(target_arch = "wasm32", no_main)]

mod state;
#[cfg(test)]
#[path = "./contract_unit_tests.rs"]
mod tests;

use atoma_demo::{ChatInteraction, Operation};
use linera_sdk::{
base::WithContractAbi,
views::{RootView, View},
Expand Down Expand Up @@ -38,11 +42,23 @@ impl Contract for ApplicationContract {

async fn instantiate(&mut self, _argument: Self::InstantiationArgument) {}

async fn execute_operation(&mut self, _operation: Self::Operation) -> Self::Response {}
async fn execute_operation(&mut self, operation: Self::Operation) -> Self::Response {
let Operation::LogChatInteraction { interaction } = operation;

self.log_chat_interaction(interaction);
}

async fn execute_message(&mut self, _message: Self::Message) {}

async fn store(mut self) {
self.state.save().await.expect("Failed to save state");
}
}

impl ApplicationContract {
/// Handles an [`Operation::LogChatInteraction`] by adding a [`ChatInteraction`] to the chat
/// log.
fn log_chat_interaction(&mut self, interaction: ChatInteraction) {
self.state.chat_log.push(interaction);
}
}
36 changes: 36 additions & 0 deletions src/contract_unit_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Zefchain Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use atoma_demo::{ChatInteraction, Operation};
use linera_sdk::{util::BlockingWait, Contract, ContractRuntime};
use test_strategy::proptest;

use super::ApplicationContract;

/// Tests if chat interactions are logged on chain.
#[proptest]
fn chat_interactions_are_logged_on_chain(interactions: Vec<ChatInteraction>) {
let mut contract = setup_contract();

for interaction in interactions.clone() {
contract
.execute_operation(Operation::LogChatInteraction { interaction })
.blocking_wait();
}

let logged_interactions = contract
.state
.chat_log
.read(..)
.blocking_wait()
.expect("Failed to read logged chat interactions from the state");

assert_eq!(logged_interactions, interactions);
}

/// Creates a [`ApplicationContract`] instance to be tested.
fn setup_contract() -> ApplicationContract {
let runtime = ContractRuntime::new();

ApplicationContract::load(runtime).blocking_wait()
}
Loading

0 comments on commit 7ff0843

Please sign in to comment.