splitSysPromptPrefix function
Split system prompt blocks by content type for API cache control.
Modes:
- skipGlobalCache + useGlobalCache: up to 3 blocks, org-level caching.
- useGlobalCache + dynamicBoundary found: up to 4 blocks with global cache.
- Default: up to 3 blocks with org-level caching.
Implementation
List<SystemPromptBlock> splitSysPromptPrefix({
required SystemPrompt systemPrompt,
bool skipGlobalCacheForSystemPrompt = false,
bool useGlobalCacheFeature = false,
String? dynamicBoundary,
Set<String>? cliSyspromptPrefixes,
}) {
final prefixes = cliSyspromptPrefixes ?? {};
// Mode 1: MCP tools present — skip global cache on system prompt.
if (useGlobalCacheFeature && skipGlobalCacheForSystemPrompt) {
String? attributionHeader;
String? systemPromptPrefix;
final rest = <String>[];
for (final prompt in systemPrompt) {
if (prompt.isEmpty || prompt == dynamicBoundary) continue;
if (prompt.startsWith('x-anthropic-billing-header')) {
attributionHeader = prompt;
} else if (prefixes.contains(prompt)) {
systemPromptPrefix = prompt;
} else {
rest.add(prompt);
}
}
return [
if (attributionHeader != null)
SystemPromptBlock(text: attributionHeader, cacheScope: null),
if (systemPromptPrefix != null)
SystemPromptBlock(text: systemPromptPrefix, cacheScope: CacheScope.org),
if (rest.isNotEmpty)
SystemPromptBlock(text: rest.join('\n\n'), cacheScope: CacheScope.org),
];
}
// Mode 2: Global cache with dynamic boundary marker.
if (useGlobalCacheFeature && dynamicBoundary != null) {
final boundaryIndex = systemPrompt.indexWhere((s) => s == dynamicBoundary);
if (boundaryIndex != -1) {
String? attributionHeader;
String? systemPromptPrefix;
final staticBlocks = <String>[];
final dynamicBlocks = <String>[];
for (var i = 0; i < systemPrompt.length; i++) {
final block = systemPrompt[i];
if (block.isEmpty || block == dynamicBoundary) continue;
if (block.startsWith('x-anthropic-billing-header')) {
attributionHeader = block;
} else if (prefixes.contains(block)) {
systemPromptPrefix = block;
} else if (i < boundaryIndex) {
staticBlocks.add(block);
} else {
dynamicBlocks.add(block);
}
}
return [
if (attributionHeader != null)
SystemPromptBlock(text: attributionHeader, cacheScope: null),
if (systemPromptPrefix != null)
SystemPromptBlock(text: systemPromptPrefix, cacheScope: null),
if (staticBlocks.isNotEmpty)
SystemPromptBlock(
text: staticBlocks.join('\n\n'),
cacheScope: CacheScope.global,
),
if (dynamicBlocks.isNotEmpty)
SystemPromptBlock(text: dynamicBlocks.join('\n\n'), cacheScope: null),
];
}
}
// Mode 3: Default — org-level caching.
String? attributionHeader;
String? systemPromptPrefix;
final rest = <String>[];
for (final block in systemPrompt) {
if (block.isEmpty) continue;
if (block.startsWith('x-anthropic-billing-header')) {
attributionHeader = block;
} else if (prefixes.contains(block)) {
systemPromptPrefix = block;
} else {
rest.add(block);
}
}
return [
if (attributionHeader != null)
SystemPromptBlock(text: attributionHeader, cacheScope: null),
if (systemPromptPrefix != null)
SystemPromptBlock(text: systemPromptPrefix, cacheScope: CacheScope.org),
if (rest.isNotEmpty)
SystemPromptBlock(text: rest.join('\n\n'), cacheScope: CacheScope.org),
];
}