@bubblebrain-ai/bubble 0.0.16 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/internal-reminder-sanitizer.d.ts +2 -0
- package/dist/agent/internal-reminder-sanitizer.js +27 -0
- package/dist/agent.js +97 -5
- package/dist/context/budget.js +15 -0
- package/dist/debug-trace.js +14 -0
- package/dist/feishu/serve.js +1 -0
- package/dist/main.js +2 -0
- package/dist/model-catalog.d.ts +3 -0
- package/dist/model-catalog.js +38 -0
- package/dist/model-config.d.ts +3 -0
- package/dist/model-config.js +3 -0
- package/dist/prompt/compose.js +1 -1
- package/dist/prompt/reminders.js +3 -3
- package/dist/prompt/runtime.js +1 -0
- package/dist/provider-anthropic.d.ts +77 -0
- package/dist/provider-anthropic.js +544 -0
- package/dist/provider-registry.d.ts +2 -0
- package/dist/provider-registry.js +29 -3
- package/dist/provider-transform.d.ts +1 -1
- package/dist/provider-transform.js +14 -0
- package/dist/provider.d.ts +4 -1
- package/dist/provider.js +119 -40
- package/dist/session-log.js +14 -2
- package/dist/slash-commands/commands.js +4 -2
- package/dist/types.d.ts +13 -0
- package/package.json +1 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { AssistantProviderMetadata } from "../types.js";
|
|
1
2
|
export declare function formatInternalReminderBlock(kind: string, content: string): string;
|
|
2
3
|
export declare function formatInternalContextBlock(kind: string, content: string): string;
|
|
3
4
|
export declare function sanitizeInternalReminderBlocks(text: string): string;
|
|
5
|
+
export declare function sanitizeAssistantProviderMetadata(metadata: AssistantProviderMetadata | undefined): AssistantProviderMetadata | undefined;
|
|
4
6
|
export declare function createStreamingInternalReminderSanitizer(): {
|
|
5
7
|
push(delta: string): string;
|
|
6
8
|
flush(): string;
|
|
@@ -37,6 +37,33 @@ export function sanitizeInternalReminderBlocks(text) {
|
|
|
37
37
|
const sanitizer = createStreamingInternalReminderSanitizer();
|
|
38
38
|
return sanitizer.push(text) + sanitizer.flush();
|
|
39
39
|
}
|
|
40
|
+
export function sanitizeAssistantProviderMetadata(metadata) {
|
|
41
|
+
const anthropic = metadata?.anthropic;
|
|
42
|
+
const blocks = anthropic?.contentBlocks;
|
|
43
|
+
if (!metadata || !anthropic || !blocks?.length)
|
|
44
|
+
return metadata;
|
|
45
|
+
let changed = false;
|
|
46
|
+
const sanitizedBlocks = blocks.map((block) => {
|
|
47
|
+
if (block.type !== "text" || typeof block.text !== "string") {
|
|
48
|
+
return block;
|
|
49
|
+
}
|
|
50
|
+
const sanitizedText = sanitizeInternalReminderBlocks(block.text);
|
|
51
|
+
if (sanitizedText === block.text) {
|
|
52
|
+
return block;
|
|
53
|
+
}
|
|
54
|
+
changed = true;
|
|
55
|
+
return { ...block, text: sanitizedText };
|
|
56
|
+
});
|
|
57
|
+
if (!changed)
|
|
58
|
+
return metadata;
|
|
59
|
+
return {
|
|
60
|
+
...metadata,
|
|
61
|
+
anthropic: {
|
|
62
|
+
...anthropic,
|
|
63
|
+
contentBlocks: sanitizedBlocks,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
40
67
|
export function createStreamingInternalReminderSanitizer() {
|
|
41
68
|
let pending = "";
|
|
42
69
|
const drain = (final) => {
|
package/dist/agent.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { compactMessages } from "./context/compact.js";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
import { compactMessagesWithLLM } from "./context/compact-llm.js";
|
|
8
|
-
import { getContextBudget } from "./context/budget.js";
|
|
8
|
+
import { estimateContextTokens, getContextBudget } from "./context/budget.js";
|
|
9
9
|
import { buildContextUsageSnapshot } from "./context/usage.js";
|
|
10
10
|
import { isContextOverflowError } from "./context/overflow.js";
|
|
11
11
|
import { projectMessages } from "./context/projector.js";
|
|
@@ -20,7 +20,7 @@ import { composeAbortSignals } from "./agent/budget-ledger.js";
|
|
|
20
20
|
import { assignAgentNickname, builtinAgentProfiles, mergeUsage, selectToolsForAgentProfile, validateAgentProfileTools } from "./agent/profiles.js";
|
|
21
21
|
import { snapshotSubagentThread, subagentResultFromThread } from "./agent/subagent-control.js";
|
|
22
22
|
import { isHiddenToolResult } from "./agent/discovery-barrier.js";
|
|
23
|
-
import { createStreamingInternalReminderSanitizer, sanitizeInternalReminderBlocks } from "./agent/internal-reminder-sanitizer.js";
|
|
23
|
+
import { createStreamingInternalReminderSanitizer, sanitizeAssistantProviderMetadata, sanitizeInternalReminderBlocks } from "./agent/internal-reminder-sanitizer.js";
|
|
24
24
|
import { buildSystemPrompt } from "./system-prompt.js";
|
|
25
25
|
import { isOnlyProviderProtocolArtifacts, stripProviderProtocolArtifacts } from "./provider-artifacts.js";
|
|
26
26
|
import { debugReasoningStream, summarizeDebugText } from "./reasoning-debug.js";
|
|
@@ -376,6 +376,7 @@ export class Agent {
|
|
|
376
376
|
modelId: this.apiModel,
|
|
377
377
|
};
|
|
378
378
|
const streamingToolCalls = new Map();
|
|
379
|
+
const textSanitizer = createStreamingInternalReminderSanitizer();
|
|
379
380
|
const reasoningSanitizer = createStreamingInternalReminderSanitizer();
|
|
380
381
|
let turnUsage;
|
|
381
382
|
let assistantAppended = false;
|
|
@@ -433,6 +434,7 @@ export class Agent {
|
|
|
433
434
|
toolCount: toolDefinitions.length,
|
|
434
435
|
thinkingLevel: this.thinkingLevel,
|
|
435
436
|
mode: this._mode,
|
|
437
|
+
requestFingerprint: buildProviderRequestFingerprint(projectedMessages, toolDefinitions, this.providerId),
|
|
436
438
|
}, traceContext);
|
|
437
439
|
const stream = this.provider.streamChat(projectedMessages, {
|
|
438
440
|
model: this.apiModel,
|
|
@@ -445,9 +447,14 @@ export class Agent {
|
|
|
445
447
|
throwIfAborted(abortSignal);
|
|
446
448
|
switch (chunk.type) {
|
|
447
449
|
case "text":
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
450
|
+
{
|
|
451
|
+
const sanitizedDelta = textSanitizer.push(chunk.content);
|
|
452
|
+
if (sanitizedDelta) {
|
|
453
|
+
assistantMsg.content += sanitizedDelta;
|
|
454
|
+
streamTextChars += sanitizedDelta.length;
|
|
455
|
+
yield emit({ type: "text_delta", content: sanitizedDelta });
|
|
456
|
+
}
|
|
457
|
+
}
|
|
451
458
|
break;
|
|
452
459
|
case "reasoning_delta":
|
|
453
460
|
{
|
|
@@ -468,6 +475,9 @@ export class Agent {
|
|
|
468
475
|
}
|
|
469
476
|
}
|
|
470
477
|
break;
|
|
478
|
+
case "provider_content_block":
|
|
479
|
+
appendProviderContentBlock(assistantMsg, chunk.provider, chunk.block);
|
|
480
|
+
break;
|
|
471
481
|
case "tool_call":
|
|
472
482
|
if (discoveryBarrier?.isEnabled()
|
|
473
483
|
&& (bufferedStreamingToolCallIds.has(chunk.id) || discoveryBarrier.shouldBufferStreamingToolCall(chunk.name))) {
|
|
@@ -540,6 +550,12 @@ export class Agent {
|
|
|
540
550
|
for (const update of this.drainSubagentToolUpdates())
|
|
541
551
|
yield emit(update);
|
|
542
552
|
}
|
|
553
|
+
const flushedText = textSanitizer.flush();
|
|
554
|
+
if (flushedText) {
|
|
555
|
+
assistantMsg.content += flushedText;
|
|
556
|
+
streamTextChars += flushedText.length;
|
|
557
|
+
yield emit({ type: "text_delta", content: flushedText });
|
|
558
|
+
}
|
|
543
559
|
const flushedReasoning = reasoningSanitizer.flush();
|
|
544
560
|
if (flushedReasoning) {
|
|
545
561
|
debugReasoningStream({
|
|
@@ -1525,9 +1541,15 @@ export class Agent {
|
|
|
1525
1541
|
}
|
|
1526
1542
|
}
|
|
1527
1543
|
appendMessage(message) {
|
|
1544
|
+
if (message.role === "assistant" && message.content) {
|
|
1545
|
+
message.content = sanitizeInternalReminderBlocks(message.content);
|
|
1546
|
+
}
|
|
1528
1547
|
if (message.role === "assistant" && message.reasoning) {
|
|
1529
1548
|
message.reasoning = sanitizeInternalReminderBlocks(message.reasoning);
|
|
1530
1549
|
}
|
|
1550
|
+
if (message.role === "assistant" && message.providerMetadata) {
|
|
1551
|
+
message.providerMetadata = sanitizeAssistantProviderMetadata(message.providerMetadata);
|
|
1552
|
+
}
|
|
1531
1553
|
this.messages.push(message);
|
|
1532
1554
|
traceEvent("agent_message_append", {
|
|
1533
1555
|
message: summarizeTraceMessage(message),
|
|
@@ -1682,6 +1704,76 @@ function estimateResidentChars(messages) {
|
|
|
1682
1704
|
}
|
|
1683
1705
|
return total;
|
|
1684
1706
|
}
|
|
1707
|
+
function appendProviderContentBlock(message, provider, block) {
|
|
1708
|
+
if (provider !== "anthropic")
|
|
1709
|
+
return;
|
|
1710
|
+
const current = message.providerMetadata?.anthropic?.contentBlocks ?? [];
|
|
1711
|
+
message.providerMetadata = {
|
|
1712
|
+
...message.providerMetadata,
|
|
1713
|
+
anthropic: {
|
|
1714
|
+
...message.providerMetadata?.anthropic,
|
|
1715
|
+
contentBlocks: [...current, cloneProviderRawContentBlock(block)],
|
|
1716
|
+
},
|
|
1717
|
+
};
|
|
1718
|
+
}
|
|
1719
|
+
function buildProviderRequestFingerprint(messages, tools, providerId) {
|
|
1720
|
+
const roleCounts = {};
|
|
1721
|
+
let contentChars = 0;
|
|
1722
|
+
let reasoningChars = 0;
|
|
1723
|
+
let toolResultChars = 0;
|
|
1724
|
+
let maxToolResultChars = 0;
|
|
1725
|
+
let assistantToolCalls = 0;
|
|
1726
|
+
let rawAnthropicBlocks = 0;
|
|
1727
|
+
let rawAnthropicThinkingBlocks = 0;
|
|
1728
|
+
let rawAnthropicSignatureChars = 0;
|
|
1729
|
+
for (const message of messages) {
|
|
1730
|
+
roleCounts[message.role] = (roleCounts[message.role] ?? 0) + 1;
|
|
1731
|
+
if (message.role === "assistant") {
|
|
1732
|
+
contentChars += message.content.length;
|
|
1733
|
+
reasoningChars += message.reasoning?.length ?? 0;
|
|
1734
|
+
assistantToolCalls += message.toolCalls?.length ?? 0;
|
|
1735
|
+
const blocks = message.providerMetadata?.anthropic?.contentBlocks ?? [];
|
|
1736
|
+
rawAnthropicBlocks += blocks.length;
|
|
1737
|
+
for (const block of blocks) {
|
|
1738
|
+
if (block.type === "thinking" || block.type === "redacted_thinking") {
|
|
1739
|
+
rawAnthropicThinkingBlocks += 1;
|
|
1740
|
+
}
|
|
1741
|
+
if (typeof block.signature === "string") {
|
|
1742
|
+
rawAnthropicSignatureChars += block.signature.length;
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
else if (message.role === "tool") {
|
|
1747
|
+
toolResultChars += message.content.length;
|
|
1748
|
+
maxToolResultChars = Math.max(maxToolResultChars, message.content.length);
|
|
1749
|
+
}
|
|
1750
|
+
else if (message.role === "user") {
|
|
1751
|
+
contentChars += typeof message.content === "string"
|
|
1752
|
+
? message.content.length
|
|
1753
|
+
: message.content.reduce((sum, part) => sum + (part.type === "text" ? part.text.length : part.image_url.url.length), 0);
|
|
1754
|
+
}
|
|
1755
|
+
else {
|
|
1756
|
+
contentChars += message.content.length;
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
return {
|
|
1760
|
+
roleCounts,
|
|
1761
|
+
estimatedTokens: estimateContextTokens(messages, providerId),
|
|
1762
|
+
projectedJsonBytes: Buffer.byteLength(JSON.stringify(messages), "utf8"),
|
|
1763
|
+
toolSchemaJsonBytes: Buffer.byteLength(JSON.stringify(tools), "utf8"),
|
|
1764
|
+
contentChars,
|
|
1765
|
+
reasoningChars,
|
|
1766
|
+
toolResultChars,
|
|
1767
|
+
maxToolResultChars,
|
|
1768
|
+
assistantToolCalls,
|
|
1769
|
+
rawAnthropicBlocks,
|
|
1770
|
+
rawAnthropicThinkingBlocks,
|
|
1771
|
+
rawAnthropicSignatureChars,
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
function cloneProviderRawContentBlock(block) {
|
|
1775
|
+
return JSON.parse(JSON.stringify(block));
|
|
1776
|
+
}
|
|
1685
1777
|
function throwIfAborted(signal) {
|
|
1686
1778
|
if (!signal?.aborted)
|
|
1687
1779
|
return;
|
package/dist/context/budget.js
CHANGED
|
@@ -20,6 +20,7 @@ export function estimateMessageTokens(message, providerId) {
|
|
|
20
20
|
case "assistant":
|
|
21
21
|
return estimate(message.content)
|
|
22
22
|
+ estimate(message.reasoning ?? "")
|
|
23
|
+
+ estimateProviderMetadataOverhead(message.providerMetadata, providerId)
|
|
23
24
|
+ (message.toolCalls?.reduce((sum, toolCall) => sum + estimate(toolCall.arguments) + 12, 0) ?? 0)
|
|
24
25
|
+ 8;
|
|
25
26
|
case "user":
|
|
@@ -34,6 +35,20 @@ export function estimateMessageTokens(message, providerId) {
|
|
|
34
35
|
}, 8);
|
|
35
36
|
}
|
|
36
37
|
}
|
|
38
|
+
function estimateProviderMetadataOverhead(metadata, providerId) {
|
|
39
|
+
const blocks = metadata?.anthropic?.contentBlocks;
|
|
40
|
+
if (!blocks || blocks.length === 0)
|
|
41
|
+
return 0;
|
|
42
|
+
const estimate = (text) => estimateTextTokens(text, providerId);
|
|
43
|
+
return blocks.reduce((sum, block) => {
|
|
44
|
+
let overhead = 0;
|
|
45
|
+
if (typeof block.signature === "string")
|
|
46
|
+
overhead += estimate(block.signature);
|
|
47
|
+
if (block.type === "redacted_thinking" && typeof block.data === "string")
|
|
48
|
+
overhead += estimate(block.data);
|
|
49
|
+
return sum + overhead;
|
|
50
|
+
}, 0);
|
|
51
|
+
}
|
|
37
52
|
export function estimateContextTokens(messages, providerId) {
|
|
38
53
|
return messages.reduce((sum, message) => sum + estimateMessageTokens(message, providerId), 0);
|
|
39
54
|
}
|
package/dist/debug-trace.js
CHANGED
|
@@ -112,6 +112,7 @@ export function summarizeTraceMessage(message) {
|
|
|
112
112
|
content: summarizeTraceText(message.content),
|
|
113
113
|
reasoning: summarizeTraceText(message.reasoning ?? ""),
|
|
114
114
|
error: message.error,
|
|
115
|
+
providerMetadata: summarizeAssistantProviderMetadata(message),
|
|
115
116
|
toolCalls: message.toolCalls?.map((call) => ({
|
|
116
117
|
id: call.id,
|
|
117
118
|
name: call.name,
|
|
@@ -141,6 +142,19 @@ export function summarizeTraceMessage(message) {
|
|
|
141
142
|
content: summarizeTraceText(message.content),
|
|
142
143
|
};
|
|
143
144
|
}
|
|
145
|
+
function summarizeAssistantProviderMetadata(message) {
|
|
146
|
+
const blocks = message.providerMetadata?.anthropic?.contentBlocks;
|
|
147
|
+
if (!blocks || blocks.length === 0)
|
|
148
|
+
return undefined;
|
|
149
|
+
return {
|
|
150
|
+
anthropic: {
|
|
151
|
+
contentBlocks: blocks.length,
|
|
152
|
+
thinkingBlocks: blocks.filter((block) => block.type === "thinking" || block.type === "redacted_thinking").length,
|
|
153
|
+
signatureChars: blocks.reduce((sum, block) => sum + (typeof block.signature === "string" ? block.signature.length : 0), 0),
|
|
154
|
+
types: blocks.map((block) => block.type).slice(0, 32),
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
144
158
|
export function summarizeTraceToolResult(result) {
|
|
145
159
|
return {
|
|
146
160
|
content: summarizeTraceText(result.content),
|
package/dist/feishu/serve.js
CHANGED
|
@@ -96,6 +96,7 @@ export async function serveFeishu(opts = {}) {
|
|
|
96
96
|
apiKey,
|
|
97
97
|
baseURL,
|
|
98
98
|
promptCacheKey,
|
|
99
|
+
protocol: providerRegistry.getConfigured().find((provider) => provider.id === providerId)?.protocol,
|
|
99
100
|
openAICodexAuth: providerRegistry.createOpenAICodexAuthAdapter(providerId),
|
|
100
101
|
});
|
|
101
102
|
const createProviderForRoute = async (route, promptCacheKey) => {
|
package/dist/main.js
CHANGED
|
@@ -83,6 +83,7 @@ async function main() {
|
|
|
83
83
|
baseURL: defaultProvider.baseURL,
|
|
84
84
|
thinkingLevel: args.thinkingLevel,
|
|
85
85
|
promptCacheKey: sessionPromptCacheKey,
|
|
86
|
+
protocol: defaultProvider.protocol,
|
|
86
87
|
openAICodexAuth: registry.createOpenAICodexAuthAdapter(defaultProvider.id),
|
|
87
88
|
})
|
|
88
89
|
: createUnavailableProvider(unavailableProviderMessage);
|
|
@@ -92,6 +93,7 @@ async function main() {
|
|
|
92
93
|
baseURL,
|
|
93
94
|
thinkingLevel: args.thinkingLevel,
|
|
94
95
|
promptCacheKey: sessionPromptCacheKey,
|
|
96
|
+
protocol: registry.getConfigured().find((provider) => provider.id === providerId)?.protocol,
|
|
95
97
|
openAICodexAuth: registry.createOpenAICodexAuthAdapter(providerId),
|
|
96
98
|
});
|
|
97
99
|
const createProviderForRoute = async (route) => {
|
package/dist/model-catalog.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { ReasoningEffort } from "./types.js";
|
|
2
|
+
export type ProviderProtocol = "openai-chat" | "anthropic-messages";
|
|
2
3
|
export interface BuiltinProviderDefinition {
|
|
3
4
|
id: string;
|
|
4
5
|
name: string;
|
|
5
6
|
baseURL: string;
|
|
7
|
+
protocol?: ProviderProtocol;
|
|
8
|
+
hidden?: boolean;
|
|
6
9
|
supportsOAuth?: boolean;
|
|
7
10
|
}
|
|
8
11
|
export interface BuiltinModelDefinition {
|
package/dist/model-catalog.js
CHANGED
|
@@ -2,6 +2,7 @@ export const BUILTIN_PROVIDERS = [
|
|
|
2
2
|
{ id: "openrouter", name: "OpenRouter", baseURL: "https://openrouter.ai/api/v1" },
|
|
3
3
|
{ id: "openai", name: "OpenAI", baseURL: "https://api.openai.com/v1", supportsOAuth: true },
|
|
4
4
|
{ id: "openai-codex", name: "OpenAI Codex (ChatGPT)", baseURL: "https://chatgpt.com/backend-api" },
|
|
5
|
+
{ id: "anthropic", name: "Anthropic", baseURL: "https://api.anthropic.com", protocol: "anthropic-messages" },
|
|
5
6
|
{ id: "deepseek", name: "DeepSeek", baseURL: "https://api.deepseek.com" },
|
|
6
7
|
{ id: "google", name: "Google", baseURL: "https://generativelanguage.googleapis.com/v1beta/openai" },
|
|
7
8
|
{ id: "zhipuai", name: "Zhipu AI", baseURL: "https://open.bigmodel.cn/api/paas/v4" },
|
|
@@ -9,6 +10,9 @@ export const BUILTIN_PROVIDERS = [
|
|
|
9
10
|
{ id: "zai", name: "Z.AI", baseURL: "https://api.z.ai/api/paas/v4" },
|
|
10
11
|
{ id: "zai-coding-plan", name: "Z.AI Coding Plan", baseURL: "https://api.z.ai/api/coding/paas/v4" },
|
|
11
12
|
{ id: "alibaba", name: "Alibaba DashScope", baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1" },
|
|
13
|
+
{ id: "minimax", name: "MiniMax Token Plan", baseURL: "https://api.minimaxi.com/anthropic", protocol: "anthropic-messages" },
|
|
14
|
+
{ id: "minimax-openai", name: "MiniMax (OpenAI Compatible)", baseURL: "https://api.minimaxi.com/v1" },
|
|
15
|
+
{ id: "minimax-anthropic", name: "MiniMax (Anthropic Compatible)", baseURL: "https://api.minimaxi.com/anthropic", protocol: "anthropic-messages", hidden: true },
|
|
12
16
|
{ id: "stepfun", name: "StepFun Step Plan", baseURL: "https://api.stepfun.com/step_plan/v1" },
|
|
13
17
|
{ id: "moonshot-cn", name: "Moonshot (国内 platform.moonshot.cn)", baseURL: "https://api.moonshot.cn/v1" },
|
|
14
18
|
{ id: "moonshot-intl", name: "Moonshot (海外 platform.moonshot.ai)", baseURL: "https://api.moonshot.ai/v1" },
|
|
@@ -26,6 +30,10 @@ const OPENAI_CHAT_LEVELS = ["off"];
|
|
|
26
30
|
const TOGGLE_THINKING_LEVELS = ["off", "medium"];
|
|
27
31
|
const DEEPSEEK_V4_LEVELS = ["high", "max"];
|
|
28
32
|
const STEPFUN_REASONING_LEVELS = ["off", "low", "medium", "high"];
|
|
33
|
+
const MINIMAX_M3_REASONING_LEVELS = ["off", "medium"];
|
|
34
|
+
const MINIMAX_REASONING_LEVELS = ["medium"];
|
|
35
|
+
const ANTHROPIC_ADAPTIVE_LEVELS = ["off", "medium"];
|
|
36
|
+
const ANTHROPIC_CHAT_LEVELS = ["off"];
|
|
29
37
|
export const BUILTIN_MODELS = [
|
|
30
38
|
{ id: "gpt-5.5", name: "gpt-5.5", providerId: "openai-codex", reasoningLevels: ALL_OPENAI_LEVELS, contextWindow: 272000, toolOutputTokenLimit: 10000 },
|
|
31
39
|
{ id: "gpt-5.4", name: "gpt-5.4", providerId: "openai-codex", reasoningLevels: ALL_OPENAI_LEVELS, contextWindow: 272000 },
|
|
@@ -42,6 +50,9 @@ export const BUILTIN_MODELS = [
|
|
|
42
50
|
{ id: "o1-preview", name: "o1-preview", providerId: "openai", reasoningLevels: ["off", "low", "medium", "high"], contextWindow: 128000 },
|
|
43
51
|
{ id: "o1-mini", name: "o1-mini", providerId: "openai", reasoningLevels: ["off", "low", "medium", "high"], contextWindow: 128000 },
|
|
44
52
|
{ id: "gpt-4-turbo", name: "gpt-4-turbo", providerId: "openai", reasoningLevels: OPENAI_CHAT_LEVELS, contextWindow: 128000 },
|
|
53
|
+
{ id: "claude-opus-4-8", name: "Claude Opus 4.8", providerId: "anthropic", reasoningLevels: ANTHROPIC_ADAPTIVE_LEVELS, contextWindow: 1000000 },
|
|
54
|
+
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", providerId: "anthropic", reasoningLevels: ANTHROPIC_ADAPTIVE_LEVELS, contextWindow: 1000000 },
|
|
55
|
+
{ id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5", providerId: "anthropic", reasoningLevels: ANTHROPIC_CHAT_LEVELS, contextWindow: 200000 },
|
|
45
56
|
{ id: "deepseek-v4-flash", name: "deepseek-v4-flash", providerId: "deepseek", reasoningLevels: DEEPSEEK_V4_LEVELS, contextWindow: 1048576 },
|
|
46
57
|
{ id: "deepseek-v4-pro", name: "deepseek-v4-pro", providerId: "deepseek", reasoningLevels: DEEPSEEK_V4_LEVELS, contextWindow: 1048576 },
|
|
47
58
|
{ id: "gemini-2.5-pro-preview-03-25", name: "gemini-2.5-pro-preview-03-25", providerId: "google", reasoningLevels: ["off", "low", "high"], contextWindow: 128000 },
|
|
@@ -61,6 +72,33 @@ export const BUILTIN_MODELS = [
|
|
|
61
72
|
{ id: "glm-4.6", name: "GLM-4.6", providerId: "zai-coding-plan", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 200000 },
|
|
62
73
|
{ id: "qwen3.6-plus", name: "Qwen3.6 Plus", providerId: "alibaba", reasoningLevels: ["off"], contextWindow: 1048576 },
|
|
63
74
|
{ id: "qwen3.7-max", name: "Qwen3.7 Max", providerId: "alibaba", reasoningLevels: ["off"], contextWindow: 1048576 },
|
|
75
|
+
{ id: "MiniMax-M3", name: "MiniMax M3", providerId: "minimax", reasoningLevels: MINIMAX_M3_REASONING_LEVELS, contextWindow: 1000000 },
|
|
76
|
+
{ id: "MiniMax-M2.7", name: "MiniMax M2.7", providerId: "minimax", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
77
|
+
{ id: "MiniMax-M2.7-highspeed", name: "MiniMax M2.7 Highspeed", providerId: "minimax", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
78
|
+
{ id: "MiniMax-M2.5", name: "MiniMax M2.5", providerId: "minimax", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
79
|
+
{ id: "MiniMax-M2.5-highspeed", name: "MiniMax M2.5 Highspeed", providerId: "minimax", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
80
|
+
{ id: "MiniMax-M2.1", name: "MiniMax M2.1", providerId: "minimax", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
81
|
+
{ id: "MiniMax-M2.1-highspeed", name: "MiniMax M2.1 Highspeed", providerId: "minimax", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
82
|
+
{ id: "MiniMax-M2", name: "MiniMax M2", providerId: "minimax", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
83
|
+
{ id: "M2-her", name: "M2-her", providerId: "minimax", reasoningLevels: ["off"], contextWindow: 64000 },
|
|
84
|
+
{ id: "MiniMax-M3", name: "MiniMax M3", providerId: "minimax-openai", reasoningLevels: MINIMAX_M3_REASONING_LEVELS, contextWindow: 1000000 },
|
|
85
|
+
{ id: "MiniMax-M2.7", name: "MiniMax M2.7", providerId: "minimax-openai", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
86
|
+
{ id: "MiniMax-M2.7-highspeed", name: "MiniMax M2.7 Highspeed", providerId: "minimax-openai", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
87
|
+
{ id: "MiniMax-M2.5", name: "MiniMax M2.5", providerId: "minimax-openai", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
88
|
+
{ id: "MiniMax-M2.5-highspeed", name: "MiniMax M2.5 Highspeed", providerId: "minimax-openai", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
89
|
+
{ id: "MiniMax-M2.1", name: "MiniMax M2.1", providerId: "minimax-openai", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
90
|
+
{ id: "MiniMax-M2.1-highspeed", name: "MiniMax M2.1 Highspeed", providerId: "minimax-openai", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
91
|
+
{ id: "MiniMax-M2", name: "MiniMax M2", providerId: "minimax-openai", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
92
|
+
{ id: "M2-her", name: "M2-her", providerId: "minimax-openai", reasoningLevels: ["off"], contextWindow: 64000 },
|
|
93
|
+
{ id: "MiniMax-M3", name: "MiniMax M3", providerId: "minimax-anthropic", reasoningLevels: MINIMAX_M3_REASONING_LEVELS, contextWindow: 1000000 },
|
|
94
|
+
{ id: "MiniMax-M2.7", name: "MiniMax M2.7", providerId: "minimax-anthropic", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
95
|
+
{ id: "MiniMax-M2.7-highspeed", name: "MiniMax M2.7 Highspeed", providerId: "minimax-anthropic", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
96
|
+
{ id: "MiniMax-M2.5", name: "MiniMax M2.5", providerId: "minimax-anthropic", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
97
|
+
{ id: "MiniMax-M2.5-highspeed", name: "MiniMax M2.5 Highspeed", providerId: "minimax-anthropic", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
98
|
+
{ id: "MiniMax-M2.1", name: "MiniMax M2.1", providerId: "minimax-anthropic", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
99
|
+
{ id: "MiniMax-M2.1-highspeed", name: "MiniMax M2.1 Highspeed", providerId: "minimax-anthropic", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
100
|
+
{ id: "MiniMax-M2", name: "MiniMax M2", providerId: "minimax-anthropic", reasoningLevels: MINIMAX_REASONING_LEVELS, contextWindow: 204800 },
|
|
101
|
+
{ id: "M2-her", name: "M2-her", providerId: "minimax-anthropic", reasoningLevels: ["off"], contextWindow: 64000 },
|
|
64
102
|
{ id: "step-3.7-flash", name: "Step 3.7 Flash", providerId: "stepfun", reasoningLevels: STEPFUN_REASONING_LEVELS, contextWindow: 256000 },
|
|
65
103
|
{ id: "step-3.5-flash-2603", name: "Step 3.5 Flash 2603", providerId: "stepfun", reasoningLevels: STEPFUN_REASONING_LEVELS },
|
|
66
104
|
{ id: "step-3.5-flash", name: "Step 3.5 Flash", providerId: "stepfun", reasoningLevels: STEPFUN_REASONING_LEVELS },
|
package/dist/model-config.d.ts
CHANGED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* Users can define providers, API keys, base URLs, and custom models
|
|
5
5
|
* in ~/.bubble/models.json.
|
|
6
6
|
*/
|
|
7
|
+
import type { ProviderProtocol } from "./model-catalog.js";
|
|
7
8
|
import type { ModelInfo } from "./provider-registry.js";
|
|
8
9
|
export interface ProviderModelConfig {
|
|
9
10
|
baseURL?: string;
|
|
10
11
|
apiKey?: string;
|
|
12
|
+
protocol?: ProviderProtocol;
|
|
11
13
|
models?: Array<{
|
|
12
14
|
id: string;
|
|
13
15
|
name?: string;
|
|
@@ -29,4 +31,5 @@ export declare class ModelConfig {
|
|
|
29
31
|
getCustomModels(providerId: string): ModelInfo[];
|
|
30
32
|
getApiKey(providerId: string): string | undefined;
|
|
31
33
|
getBaseURL(providerId: string): string | undefined;
|
|
34
|
+
getProtocol(providerId: string): ProviderProtocol | undefined;
|
|
32
35
|
}
|
package/dist/model-config.js
CHANGED
package/dist/prompt/compose.js
CHANGED
|
@@ -38,7 +38,7 @@ function buildProviderPrompt(agentName, providerId, modelId, modelName) {
|
|
|
38
38
|
const rawModel = modelId ?? modelName ?? "";
|
|
39
39
|
const model = rawModel.includes(":") ? rawModel.split(":").slice(1).join(":") : rawModel;
|
|
40
40
|
const lowerModel = model.toLowerCase();
|
|
41
|
-
if (provider === "anthropic" || model.startsWith("claude")) {
|
|
41
|
+
if (provider === "anthropic" || provider === "minimax" || provider.endsWith("-anthropic") || model.startsWith("claude")) {
|
|
42
42
|
return buildAnthropicProviderPrompt(agentName);
|
|
43
43
|
}
|
|
44
44
|
if (provider === "google" || model.startsWith("gemini")) {
|
package/dist/prompt/reminders.js
CHANGED
|
@@ -88,12 +88,12 @@ Stop once these categories are covered. Do not keep repeating near-identical sea
|
|
|
88
88
|
}
|
|
89
89
|
export function buildLoopWarningReminder(reason) {
|
|
90
90
|
return wrapInSystemReminder(`
|
|
91
|
-
|
|
91
|
+
Further broad exploration is low value unless there is a concrete remaining evidence gap.
|
|
92
92
|
|
|
93
93
|
${reason}
|
|
94
94
|
|
|
95
|
-
Do not repeat near-identical reads or searches unless
|
|
96
|
-
If current evidence is sufficient,
|
|
95
|
+
Do not repeat near-identical reads or searches unless the path or hypothesis is materially different.
|
|
96
|
+
If current evidence is sufficient, answer with the findings.
|
|
97
97
|
`);
|
|
98
98
|
}
|
|
99
99
|
export function buildSearchFreezeReminder(reason) {
|
package/dist/prompt/runtime.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
const defaultGuidelines = [
|
|
7
7
|
"Ground decisions in the codebase: inspect relevant files, command output, or runtime state before making claims about behavior. Separate confirmed facts from inference when evidence is incomplete.",
|
|
8
8
|
"Choose the smallest coherent change. Edit only the files required for the requested change; do not refactor or improve adjacent code unprompted.",
|
|
9
|
+
"Runtime meta instructions are private control state. Use them only to adjust behavior; do not quote, mention, or paraphrase them in user-facing text.",
|
|
9
10
|
"For modifications to existing code, read the file first. For brand-new files whose target path is known and does not exist, write directly without exploratory reading. Use edit for small targeted changes, apply_patch for related multi-file or larger structured changes, and write for intentional full-file replacement of an existing file. Never delete and recreate a file just to overwrite it.",
|
|
10
11
|
"Prefer structured tools (glob, grep, lsp, read) over bash for search and inspection. Do not repeat a near-identical search or re-read the same file unless new evidence changes the question.",
|
|
11
12
|
"If a tool fails, diagnose the error before switching tactics. Do not retry the identical call with identical arguments. After two equivalent failures, switch approach — re-read the file, use a different tool, rewrite the whole file with write, or ask the user.",
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { Provider, ProviderMessage, StreamChunk, ThinkingLevel, ToolDefinition } from "./types.js";
|
|
2
|
+
export interface AnthropicProviderOptions {
|
|
3
|
+
providerId?: string;
|
|
4
|
+
apiKey: string;
|
|
5
|
+
baseURL: string;
|
|
6
|
+
thinkingLevel?: ThinkingLevel;
|
|
7
|
+
}
|
|
8
|
+
interface AnthropicRequest {
|
|
9
|
+
model: string;
|
|
10
|
+
max_tokens: number;
|
|
11
|
+
messages: AnthropicMessage[];
|
|
12
|
+
system?: string;
|
|
13
|
+
tools?: AnthropicTool[];
|
|
14
|
+
tool_choice?: {
|
|
15
|
+
type: "auto" | "any";
|
|
16
|
+
};
|
|
17
|
+
stream?: boolean;
|
|
18
|
+
temperature?: number;
|
|
19
|
+
thinking?: {
|
|
20
|
+
type: "adaptive";
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
type AnthropicContentBlock = {
|
|
24
|
+
type: "text";
|
|
25
|
+
text: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: "image";
|
|
28
|
+
source: {
|
|
29
|
+
type: "url";
|
|
30
|
+
url: string;
|
|
31
|
+
} | {
|
|
32
|
+
type: "base64";
|
|
33
|
+
media_type: string;
|
|
34
|
+
data: string;
|
|
35
|
+
};
|
|
36
|
+
} | {
|
|
37
|
+
type: "thinking";
|
|
38
|
+
thinking: string;
|
|
39
|
+
signature?: string;
|
|
40
|
+
} | {
|
|
41
|
+
type: "redacted_thinking";
|
|
42
|
+
data: string;
|
|
43
|
+
} | {
|
|
44
|
+
type: "tool_use";
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
input: Record<string, unknown>;
|
|
48
|
+
} | {
|
|
49
|
+
type: "tool_result";
|
|
50
|
+
tool_use_id: string;
|
|
51
|
+
content: string;
|
|
52
|
+
is_error?: boolean;
|
|
53
|
+
};
|
|
54
|
+
interface AnthropicMessage {
|
|
55
|
+
role: "user" | "assistant";
|
|
56
|
+
content: string | AnthropicContentBlock[];
|
|
57
|
+
}
|
|
58
|
+
interface AnthropicTool {
|
|
59
|
+
name: string;
|
|
60
|
+
description: string;
|
|
61
|
+
input_schema: ToolDefinition["parameters"];
|
|
62
|
+
}
|
|
63
|
+
export declare function createAnthropicMessagesProvider(options: AnthropicProviderOptions): Provider;
|
|
64
|
+
export declare function buildAnthropicRequest(options: AnthropicProviderOptions, messages: ProviderMessage[], chatOptions: {
|
|
65
|
+
model: string;
|
|
66
|
+
tools?: ToolDefinition[];
|
|
67
|
+
temperature?: number;
|
|
68
|
+
thinkingLevel?: ThinkingLevel;
|
|
69
|
+
stream?: boolean;
|
|
70
|
+
}): AnthropicRequest;
|
|
71
|
+
export declare function toAnthropicMessages(messages: ProviderMessage[], echoThinking?: boolean): {
|
|
72
|
+
system: string;
|
|
73
|
+
messages: AnthropicMessage[];
|
|
74
|
+
};
|
|
75
|
+
export declare function translateAnthropicStream(events: AsyncIterable<Record<string, unknown>>): AsyncIterable<StreamChunk>;
|
|
76
|
+
export declare function readSseEvents(response: Response): AsyncIterable<Record<string, unknown>>;
|
|
77
|
+
export {};
|