feat(coding-agent): merge origin/main into model runtime facade
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import type { Context, Tool } from "../types.ts";
|
||||
|
||||
type ToolNameNormalizer = (name: string) => string;
|
||||
|
||||
const identityToolName: ToolNameNormalizer = (name) => name;
|
||||
|
||||
/** Split current tools into prefix and transcript-loaded definitions. */
|
||||
export function splitDeferredTools(
|
||||
context: Context,
|
||||
enabled: boolean,
|
||||
normalizeName: ToolNameNormalizer = identityToolName,
|
||||
): { immediate: Tool[]; deferred: Map<string, Tool> } {
|
||||
const uniqueTools = new Map<string, Tool>();
|
||||
for (const tool of context.tools ?? []) uniqueTools.set(normalizeName(tool.name), tool);
|
||||
if (!enabled) return { immediate: [...uniqueTools.values()], deferred: new Map() };
|
||||
|
||||
const deferredNames = new Set<string>();
|
||||
const usedNames = new Set<string>();
|
||||
for (const message of context.messages) {
|
||||
if (message.role === "assistant") {
|
||||
for (const block of message.content) {
|
||||
if (block.type === "toolCall") usedNames.add(normalizeName(block.name));
|
||||
}
|
||||
} else if (message.role === "toolResult") {
|
||||
for (const name of message.addedToolNames ?? []) {
|
||||
const normalizedName = normalizeName(name);
|
||||
if (!usedNames.has(normalizedName)) deferredNames.add(normalizedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const immediate: Tool[] = [];
|
||||
const deferred = new Map<string, Tool>();
|
||||
for (const [name, tool] of uniqueTools) {
|
||||
if (deferredNames.has(name)) deferred.set(name, tool);
|
||||
else immediate.push(tool);
|
||||
}
|
||||
return { immediate, deferred };
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { AssistantMessage, Context, ImageContent, Message, TextContent, Usage } from "../types.ts";
|
||||
import type { AssistantMessage, Context, ImageContent, Message, TextContent, Tool, Usage } from "../types.ts";
|
||||
|
||||
export interface ContextUsageEstimate {
|
||||
/** Estimated total context tokens. */
|
||||
@@ -102,6 +102,11 @@ function estimateMessages(messages: readonly Message[]): ContextUsageEstimate {
|
||||
return { tokens, usageTokens: 0, trailingTokens: tokens, lastUsageIndex: null };
|
||||
}
|
||||
|
||||
function estimateToolsTokens(tools: readonly Tool[] | undefined): number {
|
||||
if (!tools || tools.length === 0) return 0;
|
||||
return estimateTextTokens(safeJsonStringify(tools));
|
||||
}
|
||||
|
||||
function isMessageArray(value: Context | readonly Message[]): value is readonly Message[] {
|
||||
return Array.isArray(value);
|
||||
}
|
||||
@@ -110,13 +115,25 @@ export function estimateContextTokens(context: Context | readonly Message[]): Co
|
||||
if (isMessageArray(context)) return estimateMessages(context);
|
||||
|
||||
const estimate = estimateMessages(context.messages);
|
||||
if (estimate.lastUsageIndex !== null) return estimate;
|
||||
|
||||
let prefixTokens = context.systemPrompt ? estimateTextTokens(context.systemPrompt) : 0;
|
||||
if (context.tools && context.tools.length > 0) {
|
||||
prefixTokens += estimateTextTokens(safeJsonStringify(context.tools));
|
||||
if (estimate.lastUsageIndex !== null) {
|
||||
const addedNames = new Set(
|
||||
context.messages
|
||||
.slice(estimate.lastUsageIndex + 1)
|
||||
.filter((message) => message.role === "toolResult")
|
||||
.flatMap((message) => message.addedToolNames ?? []),
|
||||
);
|
||||
const addedToolTokens = estimateToolsTokens(context.tools?.filter((tool) => addedNames.has(tool.name)));
|
||||
return {
|
||||
tokens: estimate.tokens + addedToolTokens,
|
||||
usageTokens: estimate.usageTokens,
|
||||
trailingTokens: estimate.trailingTokens + addedToolTokens,
|
||||
lastUsageIndex: estimate.lastUsageIndex,
|
||||
};
|
||||
}
|
||||
|
||||
const prefixTokens =
|
||||
(context.systemPrompt ? estimateTextTokens(context.systemPrompt) : 0) + estimateToolsTokens(context.tools);
|
||||
|
||||
return {
|
||||
tokens: estimate.tokens + prefixTokens,
|
||||
usageTokens: estimate.usageTokens,
|
||||
|
||||
Reference in New Issue
Block a user