The-Agency/lib/src/api/request_builder.dart

221 lines
5.4 KiB
Dart

// Request builder to construct Anthropic Message API requests
// Ported from old_repo/services/api/claude.ts
import "dart:io";
import "api_types.dart";
// builds a message api request with all the standard options
class MessageRequestBuilder {
final String model;
final int maxTokens;
final List<Map<String, dynamic>> messages;
String? _systemPrompt;
double? _temperature;
List<Map<String, dynamic>>? _tools;
String? _toolChoice;
Map<String, dynamic>? _metadata;
MessageRequestBuilder({
required this.model,
required this.maxTokens,
required this.messages,
});
MessageRequestBuilder withSystem(String system) {
_systemPrompt = system;
return this;
}
MessageRequestBuilder withTemperature(double temp) {
_temperature = temp;
return this;
}
MessageRequestBuilder withTools(List<Map<String, dynamic>> tools) {
_tools = tools;
return this;
}
MessageRequestBuilder withToolChoice(String choice) {
_toolChoice = choice;
return this;
}
MessageRequestBuilder withMetadata(Map<String, dynamic> metadata) {
_metadata = metadata;
return this;
}
MessageRequest build() {
return MessageRequest(
model: model,
maxTokens: maxTokens,
messages: messages,
systemPrompt: _systemPrompt,
temperature: _temperature,
tools: _tools,
toolChoice: _toolChoice,
metadata: _metadata,
);
}
}
// helpers to add headers for API requests
class HeaderBuilder {
final Map<String, String> _headers = {};
HeaderBuilder() {
_initializeDefaultHeaders();
}
void _initializeDefaultHeaders() {
// Add standard headers for API requests
final env = Platform.environment;
// Session tracking
if (env.containsKey("CLAUDE_CODE_SESSION_ID")) {
_headers["X-Claude-Code-Session-Id"] = env["CLAUDE_CODE_SESSION_ID"]!;
}
// Remote tracking (if in a container)
if (env.containsKey("CLAUDE_CODE_CONTAINER_ID")) {
_headers["x-claude-remote-container-id"] = env["CLAUDE_CODE_CONTAINER_ID"]!;
}
if (env.containsKey("CLAUDE_CODE_REMOTE_SESSION_ID")) {
_headers["x-claude-remote-session-id"] = env["CLAUDE_CODE_REMOTE_SESSION_ID"]!;
}
// App identifier
_headers["x-app"] = "cli";
// User agent from utils would go here (TODO when http client created)
_headers["User-Agent"] = "clawd_code/0.1.0";
}
void addCustomHeader(String name, String value) {
_headers[name] = value;
}
void addAuthHeader(String apiKey) {
_headers["Authorization"] = "Bearer $apiKey";
}
void addOpenRouterHeaders() {
_headers["HTTP-Referer"] = "clawd_code";
_headers["X-Title"] = "clawd_code";
}
// parse custom headers from env var (newline or semicolon separated)
void addCustomHeadersFromEnv() {
final env = Platform.environment;
final customHeadersEnv = env["ANTHROPIC_CUSTOM_HEADERS"];
if (customHeadersEnv == null || customHeadersEnv.isEmpty) return;
final headerStrings = customHeadersEnv.split(RegExp(r"\n|\r\n"));
for (final headerString in headerStrings) {
if (headerString.trim().isEmpty) continue;
// parse "Name: Value" format, split on first colon
final colonIdx = headerString.indexOf(":");
if (colonIdx == -1) continue;
final name = headerString.substring(0, colonIdx).trim();
final value = headerString.substring(colonIdx + 1).trim();
if (name.isNotEmpty) {
_headers[name] = value;
}
}
}
Map<String, String> build() {
return Map.unmodifiable(_headers);
}
}
// builds user and assistant message objects for the API
class MessageBuilder {
// create a user message
static Map<String, dynamic> createUserMessage(String content) {
return {
"role": "user",
"content": content,
};
}
// create a user message with mixed content (text + tool results)
static Map<String, dynamic> createUserMessageWithContent(
List<Map<String, dynamic>> contentBlocks,
) {
return {
"role": "user",
"content": contentBlocks,
};
}
// create assistant message with text content
static Map<String, dynamic> createAssistantMessage(String content) {
return {
"role": "assistant",
"content": [
{
"type": "text",
"text": content,
}
],
};
}
// create assistant message with tool use
static Map<String, dynamic> createAssistantMessageWithToolUse(
String toolId,
String toolName,
Map<String, dynamic> toolInput,
) {
return {
"role": "assistant",
"content": [
{
"type": "tool_use",
"id": toolId,
"name": toolName,
"input": toolInput,
}
],
};
}
// add tool result to existing user message
static Map<String, dynamic> createToolResultContent(
String toolUseId,
String content,
) {
return {
"type": "tool_result",
"tool_use_id": toolUseId,
"content": content,
};
}
}
// normalize message content for sending to API
List<Map<String, dynamic>> normalizeMessagesForApi(
List<Map<String, dynamic>> messages,
) {
// basic validation and normalization
// in real implementation would handle various message formats
return messages;
}
// normalize content from api response
dynamic normalizeContentFromApi(dynamic content) {
if (content is! List) return content;
// ensure all blocks have proper types
return List.from(content);
}