Nothing
# Test Shared State: Session Environment Coupling for Multi-Agent Data Sharing
# --- Mock Model Helper ---
MockModel <- R6::R6Class("MockModel",
inherit = LanguageModelV1,
public = list(
provider = "mock",
model_id = "mock-model",
responses = list(),
last_params = NULL, # Added to capture parameters
initialize = function(responses = list()) {
self$responses <- responses
},
do_generate = function(params) {
self$last_params <- params # Capture params
if (length(self$responses) == 0) {
return(list(text = "Mock response", tool_calls = NULL))
}
# Pop the first response
resp <- self$responses[[1]]
self$responses <- self$responses[-1]
# Allow response to be a function of params
if (is.function(resp)) {
return(resp(params))
}
return(resp)
},
add_response = function(text = NULL, tool_calls = NULL) {
self$responses <- c(self$responses, list(list(
text = text,
tool_calls = tool_calls,
finish_reason = "stop",
usage = list(total_tokens = 10)
)))
},
format_tool_result = function(tool_call_id, tool_name, result) {
list(
role = "tool",
tool_call_id = tool_call_id,
name = tool_name,
content = result
)
}
)
)
# --- Tests: Tool Environment Parameter ---
test_that("Tool$run passes .envir in args", {
# A tool that reads from environment via .envir
reader_tool <- Tool$new(
name = "read_x",
description = "Read variable x from environment",
parameters = z_object(.dummy = z_string("Unused")),
execute = function(args) {
if (!is.null(args$.envir) && exists("x", envir = args$.envir)) {
get("x", envir = args$.envir)
} else {
"x not found"
}
}
)
# Create test environment
test_env <- new.env()
test_env$x <- 42
# Without envir - should not find x
result_without <- reader_tool$run(list())
expect_equal(result_without, "x not found")
# With envir - should find x via .envir
result_with <- reader_tool$run(list(), envir = test_env)
expect_equal(result_with, 42)
})
test_that("Tool can modify environment via .envir", {
# A tool that assigns to environment
writer_tool <- Tool$new(
name = "write_y",
description = "Write variable y to environment",
parameters = z_object(
value = z_number("Value to assign")
),
execute = function(args) {
if (!is.null(args$.envir)) {
assign("y", args$value, envir = args$.envir)
paste("Assigned y =", args$value)
} else {
"No environment provided"
}
}
)
test_env <- new.env()
# Execute with environment
result <- writer_tool$run(list(value = 100), envir = test_env)
expect_equal(result, "Assigned y = 100")
expect_true(exists("y", envir = test_env))
expect_equal(test_env$y, 100)
})
test_that("execute_tool_calls passes environment to tools", {
# Create a tool that both reads and writes
calc_tool <- Tool$new(
name = "double_x",
description = "Double the value of x and store in result",
parameters = z_object(.dummy = z_string("Unused")),
execute = function(args) {
env <- args$.envir
x_val <- get("x", envir = env)
assign("result", x_val * 2, envir = env)
paste("Result:", x_val * 2)
}
)
tools <- list(calc_tool)
tool_calls <- list(
list(id = "call_1", name = "double_x", arguments = list())
)
test_env <- new.env()
test_env$x <- 10
# Execute with environment
results <- execute_tool_calls(tool_calls, tools, envir = test_env)
expect_length(results, 1)
expect_false(results[[1]]$is_error)
expect_true(grepl("Result: 20", results[[1]]$result))
expect_true(exists("result", envir = test_env))
expect_equal(test_env$result, 20)
})
# --- Tests: Session Integration ---
test_that("Session environment flows through generate_text to tools", {
# Create a tool that modifies session environment
loader_tool <- Tool$new(
name = "load_data",
description = "Load data into session environment",
parameters = z_object(
name = z_string("Variable name"),
value = z_number("Value to assign")
),
execute = function(args) {
if (!is.null(args$.envir)) {
assign(args$name, args$value, envir = args$.envir)
paste("Loaded", args$name, "=", args$value)
} else {
"No session environment available"
}
}
)
mock_model <- MockModel$new()
session <- ChatSession$new(model = mock_model)
# Program mock to call the tool, then return final response
mock_model$add_response(
tool_calls = list(list(
id = "call_1",
name = "load_data",
arguments = list(name = "my_data", value = 42)
))
)
mock_model$add_response(text = "Data loaded successfully")
tools <- list(loader_tool)
result <- generate_text(
model = mock_model,
prompt = "Load my_data = 42",
tools = tools,
max_steps = 5,
session = session
)
# Verify the variable was created in session environment
expect_true(exists("my_data", envir = session$get_envir()))
expect_equal(session$get_envir()$my_data, 42)
})
test_that("Agent$run passes session to tools", {
# Create a tool that modifies session environment
loader_tool <- Tool$new(
name = "set_value",
description = "Set a value in session",
parameters = z_object(value = z_number("Value")),
execute = function(args) {
if (!is.null(args$.envir)) {
assign("loaded_value", args$value, envir = args$.envir)
"Value set"
} else {
"No session"
}
}
)
mock_model <- MockModel$new()
session <- ChatSession$new(model = mock_model)
# Create agent with the tool
agent <- Agent$new(
name = "LoaderAgent",
description = "Loads data",
tools = list(loader_tool)
)
# Program mock to call tool then respond
mock_model$add_response(
tool_calls = list(list(
id = "c1",
name = "set_value",
arguments = list(value = 99)
))
)
mock_model$add_response(text = "Done")
result <- agent$run(
task = "Set value to 99",
session = session,
model = mock_model,
max_steps = 3
)
# Verify session env was modified
expect_true(exists("loaded_value", envir = session$get_envir()))
expect_equal(session$get_envir()$loaded_value, 99)
})
# --- Tests: Cross-Agent Scenario ---
test_that("LoaderAgent creates x, CalcAgent computes x * 2", {
mock_model <- MockModel$new()
session <- ChatSession$new(model = mock_model)
# LoaderAgent tool: creates x in session
load_tool <- Tool$new(
name = "create_x",
description = "Create variable x",
parameters = z_object(value = z_number("Value for x")),
execute = function(args) {
assign("x", args$value, envir = args$.envir)
paste("Created x =", args$value)
}
)
# CalcAgent tool: reads x and computes result
calc_tool <- Tool$new(
name = "compute_double",
description = "Compute x * 2",
parameters = z_object(.dummy = z_string("Unused")),
execute = function(args) {
x_val <- get("x", envir = args$.envir)
result <- x_val * 2
assign("double_x", result, envir = args$.envir)
paste("x * 2 =", result)
}
)
loader_agent <- Agent$new(
name = "LoaderAgent",
description = "Loads data",
tools = list(load_tool)
)
calc_agent <- Agent$new(
name = "CalcAgent",
description = "Does calculations",
tools = list(calc_tool)
)
# --- Simulate LoaderAgent run ---
mock_model$add_response(
tool_calls = list(list(id = "l1", name = "create_x", arguments = list(value = 10)))
)
mock_model$add_response(text = "Loaded x = 10")
loader_agent$run(
task = "Create x = 10",
session = session,
model = mock_model,
max_steps = 3
)
# Verify x exists
expect_true(exists("x", envir = session$get_envir()))
expect_equal(session$get_envir()$x, 10)
# --- Simulate CalcAgent run (sharing same session) ---
mock_model$add_response(
tool_calls = list(list(id = "c1", name = "compute_double", arguments = list()))
)
mock_model$add_response(text = "Computed x * 2 = 20")
calc_agent$run(
task = "Compute x * 2",
session = session,
model = mock_model,
max_steps = 3
)
# Verify double_x exists and has correct value
expect_true(exists("double_x", envir = session$get_envir()))
expect_equal(session$get_envir()$double_x, 20)
})
test_that("Session environment is isolated from global", {
mock_model <- MockModel$new()
session <- ChatSession$new(model = mock_model)
# Tool that creates a variable
create_tool <- Tool$new(
name = "create_secret",
description = "Create secret variable",
parameters = z_object(.dummy = z_string("Unused")),
execute = function(args) {
assign("secret_var", "session_only", envir = args$.envir)
"Secret created"
}
)
agent <- Agent$new(
name = "SecretAgent",
description = "Creates secrets",
tools = list(create_tool)
)
mock_model$add_response(
tool_calls = list(list(id = "s1", name = "create_secret", arguments = list()))
)
mock_model$add_response(text = "Done")
agent$run(
task = "Create secret",
session = session,
model = mock_model,
max_steps = 3
)
# Variable should exist in session
expect_true(exists("secret_var", envir = session$get_envir()))
# Variable should NOT exist in global
expect_false(exists("secret_var", envir = globalenv()))
})
test_that("Agent sees session environment objects in system prompt", {
mock_model <- MockModel$new()
session <- ChatSession$new(model = mock_model)
# Inject data into session environment
env <- session$get_envir()
env$important_data <- data.frame(a = 1:5)
session$set_memory("project_phase", "planning")
agent <- Agent$new(
name = "ObserverAgent",
description = "Observes environment",
system_prompt = "Tell me what you see."
)
# Using the updated MockModel that captures params
agent$run("Look around", session = session, model = mock_model)
# Inspect system prompt in the last message or system parameter
passed_messages <- mock_model$last_params$messages
# System prompt might be in 'system' param or part of messages depending on how generate_text handles it
# generate_text merges system prompt into messages if it's a list.
# Find system message
system_msg <- NULL
if (!is.null(mock_model$last_params$system)) {
system_msg <- mock_model$last_params$system
} else {
for (msg in passed_messages) {
if (msg$role == "system") {
system_msg <- msg$content
break
}
}
}
expect_true(!is.null(system_msg), info = "System message should not be null")
expect_true(grepl("\\[SHARED SESSION CONTEXT\\]", system_msg), info = "Should contain shared session header")
expect_true(grepl("important_data", system_msg), info = "Should contain important_data")
expect_true(grepl("data.frame", system_msg), info = "Should contain data.frame class")
expect_true(grepl("project_phase", system_msg), info = "Should contain memory project_phase")
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.