@bubblebrain-ai/bubble 0.0.33 → 0.0.35

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.
Files changed (61) hide show
  1. package/dist/agent/abort-errors.d.ts +2 -2
  2. package/dist/agent/budget-ledger.d.ts +4 -45
  3. package/dist/agent/budget-ledger.js +5 -75
  4. package/dist/agent/child-runner.d.ts +1 -3
  5. package/dist/agent/child-runner.js +6 -37
  6. package/dist/agent/profiles.d.ts +0 -2
  7. package/dist/agent/profiles.js +0 -3
  8. package/dist/agent/subagent-control.d.ts +5 -12
  9. package/dist/agent/subagent-control.js +0 -2
  10. package/dist/agent/subagent-store.d.ts +1 -1
  11. package/dist/agent/subagent-store.js +1 -3
  12. package/dist/agent/workflow/control.d.ts +7 -0
  13. package/dist/agent/workflow/control.js +22 -1
  14. package/dist/agent/workflow/runtime.d.ts +15 -2
  15. package/dist/agent/workflow/runtime.js +112 -30
  16. package/dist/agent.d.ts +7 -43
  17. package/dist/agent.js +50 -176
  18. package/dist/config.d.ts +1 -3
  19. package/dist/config.js +6 -5
  20. package/dist/context/overflow.js +2 -0
  21. package/dist/main.js +9 -1
  22. package/dist/model-catalog.d.ts +1 -1
  23. package/dist/model-catalog.js +25 -18
  24. package/dist/orchestrator/default-hooks.js +7 -1
  25. package/dist/prompt/delegation.d.ts +1 -1
  26. package/dist/prompt/delegation.js +21 -7
  27. package/dist/prompt/task-reminders.d.ts +1 -0
  28. package/dist/prompt/task-reminders.js +24 -1
  29. package/dist/provider-ai-sdk.d.ts +56 -0
  30. package/dist/provider-ai-sdk.js +518 -0
  31. package/dist/provider-registry.js +49 -3
  32. package/dist/provider-transform.d.ts +1 -1
  33. package/dist/provider-transform.js +8 -13
  34. package/dist/provider.js +4 -0
  35. package/dist/slash-commands/commands.js +3 -7
  36. package/dist/slash-commands/types.d.ts +1 -1
  37. package/dist/tools/agent-lifecycle.d.ts +1 -9
  38. package/dist/tools/agent-lifecycle.js +35 -263
  39. package/dist/tui-ink/app.js +51 -13
  40. package/dist/tui-ink/approval/approval-dialog.js +1 -1
  41. package/dist/tui-ink/approval/diff-view.js +4 -4
  42. package/dist/tui-ink/approval/select.js +2 -2
  43. package/dist/tui-ink/feedback-dialog.js +2 -2
  44. package/dist/tui-ink/feishu-setup-picker.js +3 -3
  45. package/dist/tui-ink/input-box.d.ts +1 -6
  46. package/dist/tui-ink/input-box.js +14 -35
  47. package/dist/tui-ink/markdown.js +11 -9
  48. package/dist/tui-ink/message-list.d.ts +5 -1
  49. package/dist/tui-ink/message-list.js +15 -2
  50. package/dist/tui-ink/model-picker.d.ts +3 -1
  51. package/dist/tui-ink/model-picker.js +25 -14
  52. package/dist/tui-ink/plan-confirm.js +1 -1
  53. package/dist/tui-ink/subagent-view.d.ts +3 -1
  54. package/dist/tui-ink/theme.d.ts +19 -2
  55. package/dist/tui-ink/theme.js +25 -8
  56. package/dist/tui-ink/welcome.d.ts +3 -2
  57. package/dist/tui-ink/welcome.js +10 -6
  58. package/dist/types.d.ts +16 -30
  59. package/dist/variant/variant-resolver.d.ts +13 -0
  60. package/dist/variant/variant-resolver.js +26 -0
  61. package/package.json +9 -3
package/dist/config.js CHANGED
@@ -45,9 +45,6 @@ function sanitizeSubagentsConfig(value) {
45
45
  if (typeof raw.maxActiveSubagents === "number" && Number.isFinite(raw.maxActiveSubagents)) {
46
46
  out.maxActiveSubagents = Math.max(1, Math.floor(raw.maxActiveSubagents));
47
47
  }
48
- if (typeof raw.childTokenCap === "number" && Number.isFinite(raw.childTokenCap)) {
49
- out.childTokenCap = Math.max(1_000, Math.floor(raw.childTokenCap));
50
- }
51
48
  return Object.keys(out).length > 0 ? out : undefined;
52
49
  }
53
50
  function sanitizeTheme(value) {
@@ -211,8 +208,12 @@ export class UserConfig {
211
208
  return sanitizeSubagentsConfig(this.data.subagents) ?? {};
212
209
  }
213
210
  }
214
- export function shouldProbeTerminalTheme(config) {
215
- return config.mode === "auto" || isLegacyBareDarkTheme(config);
211
+ export function shouldProbeTerminalTheme(_config) {
212
+ // Always probe: even a forced theme needs the real terminal background to
213
+ // decide between inheriting it (theme matches the terminal) and painting
214
+ // its own canvas (forced theme mismatching the terminal, where the
215
+ // palette's foregrounds would otherwise be unreadable).
216
+ return true;
216
217
  }
217
218
  export function effectiveThemeModeForTerminal(config, detectedTheme) {
218
219
  if (isLegacyBareDarkTheme(config) && detectedTheme === "light")
@@ -12,6 +12,8 @@ const OVERFLOW_PATTERNS = [
12
12
  /prompt is too long/i,
13
13
  /maximum context length/i,
14
14
  /too many tokens/i,
15
+ // Gemini: "The input token count (N) exceeds the maximum number of tokens allowed (M)."
16
+ /input token count.*exceeds the maximum/i,
15
17
  ];
16
18
  export function isContextOverflowError(error) {
17
19
  if (!error)
package/dist/main.js CHANGED
@@ -235,12 +235,20 @@ async function main() {
235
235
  const pickerThemeMode = effectiveThemeModeForTerminal(themeConfig, preResolvedTheme);
236
236
  const pickerResolvedTheme = pickerThemeMode === "auto" ? preResolvedTheme : pickerThemeMode;
237
237
  const { runSessionPicker } = await import("./tui-ink/run-session-picker.js");
238
+ const { canvasBackgroundFor } = await import("./tui-ink/theme.js");
239
+ // Same rule as the main TUI: a forced theme mismatching the terminal
240
+ // paints its canvas so its foregrounds stay readable.
241
+ const pickerCanvas = themeConfig.overrides?.background
242
+ ? undefined
243
+ : canvasBackgroundFor(pickerThemeMode, pickerResolvedTheme, preResolvedTheme);
238
244
  const picked = await runSessionPicker({
239
245
  currentCwd: args.cwd,
240
246
  currentSessions,
241
247
  allSessions,
242
248
  resolvedTheme: pickerResolvedTheme,
243
- themeOverrides: themeConfig.overrides,
249
+ themeOverrides: pickerCanvas
250
+ ? { ...themeConfig.overrides, background: pickerCanvas }
251
+ : themeConfig.overrides,
244
252
  });
245
253
  if (picked) {
246
254
  sessionManager = new SessionManager(picked);
@@ -1,5 +1,5 @@
1
1
  import type { ReasoningEffort } from "./types.js";
2
- export type ProviderProtocol = "openai-chat" | "anthropic-messages" | "ark-responses";
2
+ export type ProviderProtocol = "openai-chat" | "anthropic-messages" | "ark-responses" | "ai-sdk";
3
3
  export interface BuiltinProviderDefinition {
4
4
  id: string;
5
5
  name: string;
@@ -4,7 +4,10 @@ export const BUILTIN_PROVIDERS = [
4
4
  { id: "openai-codex", name: "OpenAI Codex (ChatGPT)", baseURL: "https://chatgpt.com/backend-api" },
5
5
  { id: "anthropic", name: "Anthropic", baseURL: "https://api.anthropic.com", protocol: "anthropic-messages" },
6
6
  { id: "deepseek", name: "DeepSeek", baseURL: "https://api.deepseek.com" },
7
- { id: "google", name: "Google", baseURL: "https://generativelanguage.googleapis.com/v1beta/openai" },
7
+ // Native Gemini API via the AI SDK google provider. Users who configured the
8
+ // old OpenAI-compat endpoint can keep it by setting protocol "openai-chat"
9
+ // and the /openai baseURL explicitly in models.json.
10
+ { id: "google", name: "Google Gemini", baseURL: "https://generativelanguage.googleapis.com/v1beta", protocol: "ai-sdk" },
8
11
  { id: "zhipuai", name: "Zhipu AI", baseURL: "https://open.bigmodel.cn/api/paas/v4" },
9
12
  { id: "zhipuai-coding-plan", name: "Zhipu AI Coding Plan", baseURL: "https://open.bigmodel.cn/api/coding/paas/v4" },
10
13
  { id: "zai", name: "Z.AI", baseURL: "https://api.z.ai/api/paas/v4" },
@@ -27,6 +30,8 @@ const GPT51_LEVELS = ["off", "low", "medium", "high"];
27
30
  const GPT51_CODEX_MAX_LEVELS = ["off", "low", "medium", "high", "xhigh"];
28
31
  const GPT51_CODEX_MINI_LEVELS = ["off", "medium", "high"];
29
32
  const OPENAI_CHAT_LEVELS = ["off"];
33
+ // Internal representation for APIs that expose thinking as enabled/disabled.
34
+ // UI code must render supported toggle models as on/off, not as "medium" effort.
30
35
  const TOGGLE_THINKING_LEVELS = ["off", "medium"];
31
36
  // GLM-5.2 is the first GLM to accept OpenAI-style `reasoning_effort`. The API
32
37
  // enum is none/minimal/low/medium/high/xhigh/max; we expose high and max (the
@@ -35,8 +40,8 @@ const TOGGLE_THINKING_LEVELS = ["off", "medium"];
35
40
  // is first so it is the default (getDefaultThinkingLevel falls back to levels[0]
36
41
  // when "medium" is absent), since GLM-5.2 is a thinking-on-by-default model.
37
42
  const GLM_5_2_LEVELS = ["high", "max", "off"];
38
- // kimi-k2.7-code only supports thinking mode (disabling it errors), so "off" is
39
- // not offered — the model is always in its thinking variant.
43
+ // Kimi K2.7 Code variants only support thinking mode (disabling it errors), so
44
+ // "off" is not offered — the model is always in its thinking variant.
40
45
  const KIMI_THINKING_ONLY_LEVELS = ["medium"];
41
46
  const DEEPSEEK_V4_LEVELS = ["high", "max"];
42
47
  const STEPFUN_REASONING_LEVELS = ["off", "low", "medium", "high"];
@@ -51,6 +56,10 @@ const ANTHROPIC_OPUS_EFFORT_LEVELS = ["off", "low", "medium", "high", "xhigh", "
51
56
  const ANTHROPIC_SONNET_EFFORT_LEVELS = ["off", "low", "medium", "high", "max"];
52
57
  const ANTHROPIC_FABLE_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
53
58
  const ANTHROPIC_CHAT_LEVELS = ["off"];
59
+ const GEMINI_3_LEVELS = ["low", "medium", "high"];
60
+ const GEMINI_3_FLASH_LEVELS = ["minimal", "low", "medium", "high"];
61
+ const GEMINI_25_PRO_LEVELS = ["low", "medium", "high"];
62
+ const GEMINI_25_FLASH_LEVELS = ["off", "low", "medium", "high"];
54
63
  export const BUILTIN_MODELS = [
55
64
  { id: "gpt-5.5", name: "gpt-5.5", providerId: "openai-codex", reasoningLevels: ALL_OPENAI_LEVELS, contextWindow: 272000, toolOutputTokenLimit: 10000 },
56
65
  { id: "gpt-5.4", name: "gpt-5.4", providerId: "openai-codex", reasoningLevels: ALL_OPENAI_LEVELS, contextWindow: 272000 },
@@ -73,9 +82,15 @@ export const BUILTIN_MODELS = [
73
82
  { id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5", providerId: "anthropic", reasoningLevels: ANTHROPIC_CHAT_LEVELS, contextWindow: 200000 },
74
83
  { id: "deepseek-v4-flash", name: "deepseek-v4-flash", providerId: "deepseek", reasoningLevels: DEEPSEEK_V4_LEVELS, contextWindow: 1048576 },
75
84
  { id: "deepseek-v4-pro", name: "deepseek-v4-pro", providerId: "deepseek", reasoningLevels: DEEPSEEK_V4_LEVELS, contextWindow: 1048576 },
76
- { id: "gemini-2.5-pro-preview-03-25", name: "gemini-2.5-pro-preview-03-25", providerId: "google", reasoningLevels: ["off", "low", "high"], contextWindow: 128000 },
77
- { id: "gemini-2.0-flash-001", name: "gemini-2.0-flash-001", providerId: "google", reasoningLevels: ["off"], contextWindow: 128000 },
78
- { id: "gemini-1.5-pro-latest", name: "gemini-1.5-pro-latest", providerId: "google", reasoningLevels: ["off"], contextWindow: 128000 },
85
+ // Offline/no-key fallback only: with an API key the registry replaces this
86
+ // list via fetchGeminiModels (GET /v1beta/models, newest five). Gemini 3
87
+ // exposes thinking_level (minimal/low/medium/high); 2.5 Pro cannot disable
88
+ // thinking (no "off"), 2.5 Flash can (thinkingBudget 0).
89
+ { id: "gemini-3.5-flash", name: "Gemini 3.5 Flash", providerId: "google", reasoningLevels: GEMINI_3_FLASH_LEVELS, contextWindow: 1048576 },
90
+ { id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro", providerId: "google", reasoningLevels: GEMINI_3_LEVELS, defaultReasoningLevel: "high", contextWindow: 1048576 },
91
+ { id: "gemini-3-flash-preview", name: "Gemini 3 Flash", providerId: "google", reasoningLevels: GEMINI_3_FLASH_LEVELS, contextWindow: 1048576 },
92
+ { id: "gemini-2.5-pro", name: "Gemini 2.5 Pro", providerId: "google", reasoningLevels: GEMINI_25_PRO_LEVELS, defaultReasoningLevel: "high", contextWindow: 1048576 },
93
+ { id: "gemini-2.5-flash", name: "Gemini 2.5 Flash", providerId: "google", reasoningLevels: GEMINI_25_FLASH_LEVELS, contextWindow: 1048576 },
79
94
  { id: "glm-5.2", name: "GLM-5.2", providerId: "zhipuai", reasoningLevels: GLM_5_2_LEVELS, contextWindow: 1000000 },
80
95
  { id: "glm-5.1", name: "GLM-5.1", providerId: "zhipuai", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 200000 },
81
96
  { id: "glm-4.7", name: "GLM-4.7", providerId: "zhipuai", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 204800 },
@@ -106,25 +121,17 @@ export const BUILTIN_MODELS = [
106
121
  { id: "step-3.5-flash", name: "Step 3.5 Flash", providerId: "stepfun", reasoningLevels: STEPFUN_REASONING_LEVELS },
107
122
  { id: "step-router-v1", name: "Step Router V1", providerId: "stepfun", reasoningLevels: STEPFUN_REASONING_LEVELS },
108
123
  { id: "kimi-k2.7-code", name: "Kimi K2.7 Code", providerId: "moonshot-cn", reasoningLevels: KIMI_THINKING_ONLY_LEVELS, contextWindow: 262144 },
124
+ { id: "kimi-k2.7-code-highspeed", name: "Kimi K2.7 Code Highspeed", providerId: "moonshot-cn", reasoningLevels: KIMI_THINKING_ONLY_LEVELS, contextWindow: 262144 },
109
125
  { id: "kimi-k2.6", name: "Kimi K2.6", providerId: "moonshot-cn", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
110
- { id: "k2.6-code-preview", name: "Kimi K2.6 Code Preview", providerId: "moonshot-cn", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
111
126
  { id: "kimi-k2.5", name: "Kimi K2.5", providerId: "moonshot-cn", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
112
- { id: "kimi-k2-turbo-preview", name: "Kimi K2 Turbo", providerId: "moonshot-cn", reasoningLevels: ["off"], contextWindow: 256000 },
113
- { id: "kimi-k2-0905-preview", name: "Kimi K2 0905", providerId: "moonshot-cn", reasoningLevels: ["off"], contextWindow: 256000 },
114
- { id: "kimi-k2-thinking", name: "Kimi K2 Thinking", providerId: "moonshot-cn", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
115
127
  { id: "kimi-k2.7-code", name: "Kimi K2.7 Code", providerId: "moonshot-intl", reasoningLevels: KIMI_THINKING_ONLY_LEVELS, contextWindow: 262144 },
128
+ { id: "kimi-k2.7-code-highspeed", name: "Kimi K2.7 Code Highspeed", providerId: "moonshot-intl", reasoningLevels: KIMI_THINKING_ONLY_LEVELS, contextWindow: 262144 },
116
129
  { id: "kimi-k2.6", name: "Kimi K2.6", providerId: "moonshot-intl", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
117
- { id: "k2.6-code-preview", name: "Kimi K2.6 Code Preview", providerId: "moonshot-intl", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
118
130
  { id: "kimi-k2.5", name: "Kimi K2.5", providerId: "moonshot-intl", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
119
- { id: "kimi-k2-turbo-preview", name: "Kimi K2 Turbo", providerId: "moonshot-intl", reasoningLevels: ["off"], contextWindow: 256000 },
120
- { id: "kimi-k2-0905-preview", name: "Kimi K2 0905", providerId: "moonshot-intl", reasoningLevels: ["off"], contextWindow: 256000 },
121
- { id: "kimi-k2-thinking", name: "Kimi K2 Thinking", providerId: "moonshot-intl", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
122
131
  { id: "kimi-k2.7-code", name: "Kimi K2.7 Code", providerId: "kimi-for-coding", reasoningLevels: KIMI_THINKING_ONLY_LEVELS, contextWindow: 262144 },
132
+ { id: "kimi-k2.7-code-highspeed", name: "Kimi K2.7 Code Highspeed", providerId: "kimi-for-coding", reasoningLevels: KIMI_THINKING_ONLY_LEVELS, contextWindow: 262144 },
123
133
  { id: "kimi-k2.6", name: "Kimi K2.6", providerId: "kimi-for-coding", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
124
- { id: "k2.6-code-preview", name: "Kimi K2.6 Code Preview", providerId: "kimi-for-coding", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
125
- { id: "kimi-k2-turbo-preview", name: "Kimi K2 Turbo", providerId: "kimi-for-coding", reasoningLevels: ["off"], contextWindow: 256000 },
126
- { id: "kimi-k2-0905-preview", name: "Kimi K2 0905", providerId: "kimi-for-coding", reasoningLevels: ["off"], contextWindow: 256000 },
127
- { id: "kimi-k2-thinking", name: "Kimi K2 Thinking", providerId: "kimi-for-coding", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
134
+ { id: "kimi-k2.5", name: "Kimi K2.5", providerId: "kimi-for-coding", reasoningLevels: TOGGLE_THINKING_LEVELS, contextWindow: 256000 },
128
135
  { id: "llama-3.3-70b-versatile", name: "llama-3.3-70b-versatile", providerId: "groq", reasoningLevels: ["off"], contextWindow: 32768 },
129
136
  { id: "mixtral-8x7b-32768", name: "mixtral-8x7b-32768", providerId: "groq", reasoningLevels: ["off"], contextWindow: 32768 },
130
137
  { id: "gemma-2-9b-it", name: "gemma-2-9b-it", providerId: "groq", reasoningLevels: ["off"], contextWindow: 32768 },
@@ -5,7 +5,7 @@ import { ExecutionGovernor } from "../agent/execution-governor.js";
5
5
  import { DiscoveryBarrier } from "../agent/discovery-barrier.js";
6
6
  import { arbitrateToolCall } from "../agent/tool-arbiter.js";
7
7
  import { buildEditRetryEscalationReminder, buildSmallTaskHint, buildTaskSummaryReminder, buildWorkflowPhaseReminder, } from "../prompt/reminders.js";
8
- import { reminderForTaskType } from "../prompt/task-reminders.js";
8
+ import { orchestrationRequestReminder, reminderForTaskType } from "../prompt/task-reminders.js";
9
9
  import { formatCoverageSummary, resolveWorkflowPhase } from "./workflow.js";
10
10
  import { buildSubagentLifecycleReminder } from "../agent/subagent-lifecycle-reminder.js";
11
11
  export function createDefaultHooks() {
@@ -28,6 +28,12 @@ export function createDefaultHooks() {
28
28
  if (taskReminder) {
29
29
  ctx.queueReminder(taskReminder);
30
30
  }
31
+ // User named the mechanism ("agent team" / workflow / 编排): remind at
32
+ // the decision turn, where it outweighs the parallel-spawns prior.
33
+ const orchestrationReminder = orchestrationRequestReminder(ctx.input, ctx.agent.hasToolAvailable("run_workflow"));
34
+ if (orchestrationReminder) {
35
+ ctx.queueReminder(orchestrationReminder);
36
+ }
31
37
  // Small-task hint: counterweight to the default protocol's exploration
32
38
  // bias, only fires once per run on focused one-shot requests like
33
39
  // "写个 HTML 介绍元旦". Don't issue for the same input twice.
@@ -5,7 +5,7 @@
5
5
  * and read-only-scoped, negative clauses get equal weight — the user's hard
6
6
  * constraint is "proactive, but never delegate-everything". Gated on the
7
7
  * delegation tools being present, so child agents (whose tool sets never
8
- * include spawn_agent/agent_team) never see it.
8
+ * include spawn_agent/run_workflow) never see it.
9
9
  */
10
10
  /**
11
11
  * Returns the delegation policy section when the agent actually has the
@@ -5,12 +5,19 @@
5
5
  * and read-only-scoped, negative clauses get equal weight — the user's hard
6
6
  * constraint is "proactive, but never delegate-everything". Gated on the
7
7
  * delegation tools being present, so child agents (whose tool sets never
8
- * include spawn_agent/agent_team) never see it.
8
+ * include spawn_agent/run_workflow) never see it.
9
9
  */
10
10
  const DELEGATION_POLICY = `## Delegation policy (subagents)
11
11
 
12
- You can delegate work to background subagents (spawn_agent) and batch
13
- fan-outs (agent_team). Delegate deliberately, not by default.
12
+ You can delegate work two ways: a single background subagent (spawn_agent),
13
+ or an orchestration script coordinating many subagents (run_workflow).
14
+ Delegate deliberately, not by default.
15
+
16
+ Explicit requests win, before any other rule: when the user names a
17
+ coordinated multi-agent run in any phrasing — a workflow, an orchestration,
18
+ an agent team, "fan out agents" — that means run_workflow, NOT a row of
19
+ spawn_agent calls. When they ask for a subagent, spawn one. Only when the
20
+ user has not named a mechanism do you choose by shape (below).
14
21
 
15
22
  Delegate when:
16
23
  - An investigation will clearly require more than four search or read
@@ -18,9 +25,16 @@ Delegate when:
18
25
  needs the conclusion — delegate to a subagent so the intermediate noise
19
26
  stays out of the main context. Launch multiple subagents concurrently for
20
27
  independent questions.
21
- - The task naturally splits into the same read-only investigation or
22
- analysis (review, audit, summarize) over several independent items (files,
23
- modules, endpoints) — use agent_team.
28
+ - The task fans out over many independent items (review, audit, summarize
29
+ across files, modules, endpoints) or needs staged orchestration — consider
30
+ run_workflow. Choose by shape, not by rule: a handful of subagents whose
31
+ results you want to read and react to individually favor spawn_agent; a
32
+ uniform sweep over many items, results that should be aggregated or
33
+ filtered before they reach this conversation, or control flow between
34
+ stages (pipelines, loops, retry rounds) favor a run_workflow script — each
35
+ member's full handoff stays out of your context and the script returns one
36
+ digested result. Failed agent() calls resolve to null, so report which
37
+ items came back null instead of silently dropping them.
24
38
  - A side-investigation is independent of your current main-line work and can
25
39
  run in the background while you continue.
26
40
 
@@ -51,7 +65,7 @@ Do NOT delegate when:
51
65
  When in doubt about a one-off task, do it yourself. When a task is clearly
52
66
  the same read-only operation over three or more independent items — where
53
67
  each item alone would take more than a couple of tool calls — prefer
54
- agent_team over doing them sequentially yourself. For just two small items,
68
+ run_workflow over doing them sequentially yourself. For just two small items,
55
69
  do them yourself with parallel tool calls.`;
56
70
  /**
57
71
  * Returns the delegation policy section when the agent actually has the
@@ -4,3 +4,4 @@ export interface TaskReminderOptions {
4
4
  canDelegate?: boolean;
5
5
  }
6
6
  export declare function reminderForTaskType(taskType: TaskType, options?: TaskReminderOptions): string | undefined;
7
+ export declare function orchestrationRequestReminder(input: string | import("../types.js").ContentPart[], canRunWorkflow: boolean): string | undefined;
@@ -6,7 +6,7 @@ import { wrapInSystemReminder } from "./reminders.js";
6
6
  * keeps it away from ordinary implementation/debugging turns, so it cannot
7
7
  * amplify over-delegation.
8
8
  */
9
- const DELEGATION_NUDGE = "- If answering needs scanning many files and only the conclusion matters, delegate to a background subagent (spawn_agent); when it is the same read-only question over several independent items, fan out with agent_team.";
9
+ const DELEGATION_NUDGE = "- If answering needs scanning many files and only the conclusion matters, delegate to a background subagent (spawn_agent); when it is the same read-only question over several independent items, fan out with a run_workflow script.";
10
10
  export function reminderForTaskType(taskType, options = {}) {
11
11
  switch (taskType) {
12
12
  case "debugging":
@@ -62,3 +62,26 @@ Product discussion workflow:
62
62
  return undefined;
63
63
  }
64
64
  }
65
+ /**
66
+ * Deterministic detector for an explicit user request for a coordinated
67
+ * multi-agent run. Three rounds of prompt wording lost to the model's
68
+ * "agent team = parallel spawns" prior in live tests (opus-4.8, 2026-07-06);
69
+ * per the task-reminder principle above, a reminder injected at the decision
70
+ * turn is the lever that actually works — the harness remembers so the model
71
+ * does not have to.
72
+ */
73
+ const ORCHESTRATION_REQUEST = /\b(?:workflows?|orchestrat\w*|agent[ -]?teams?|fan[ -]?out)\b|工作流|编排|(?:智能体|代理|agent)\s*(?:团队|小队)/i;
74
+ export function orchestrationRequestReminder(input, canRunWorkflow) {
75
+ if (!canRunWorkflow)
76
+ return undefined;
77
+ const text = typeof input === "string"
78
+ ? input
79
+ : input.map((part) => ("text" in part ? String(part.text ?? "") : "")).join(" ");
80
+ if (!ORCHESTRATION_REQUEST.test(text))
81
+ return undefined;
82
+ return [
83
+ "- This message explicitly asks for a coordinated multi-agent run (a workflow / orchestration / agent team).",
84
+ "Honor it with ONE run_workflow call whose script covers the whole fan-out.",
85
+ "Do not substitute parallel spawn_agent calls this turn — the user named the mechanism.",
86
+ ].join(" ");
87
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * AI SDK provider backend ("ai-sdk" protocol).
3
+ *
4
+ * Consumes AI SDK provider packages at the LanguageModelV3 spec layer
5
+ * (`model.doStream`) rather than through the high-level `streamText` API:
6
+ * pre-stream HTTP errors throw natively (which our retry/rate-limit contract
7
+ * needs), tool-call inputs arrive as JSON strings (matching `argumentsFull`),
8
+ * and no step machinery or extra dependencies come along.
9
+ *
10
+ * Registered providers: google (Gemini native API). Adding another AI SDK
11
+ * provider is one entry in AI_SDK_PROVIDER_FACTORIES.
12
+ */
13
+ import { type ProviderFetch } from "./network/provider-transport.js";
14
+ import type { Provider, ReasoningEffort, ThinkingLevel } from "./types.js";
15
+ export interface AiSdkProviderOptions {
16
+ providerId?: string;
17
+ apiKey: string;
18
+ baseURL?: string;
19
+ thinkingLevel?: ThinkingLevel;
20
+ /** Transport override for tests; defaults to the shared provider fetch. */
21
+ fetch?: ProviderFetch;
22
+ }
23
+ export declare function isAiSdkProviderId(providerId: string | undefined): boolean;
24
+ export declare function createAiSdkProvider(options: AiSdkProviderOptions): Provider;
25
+ export interface GeminiModelDescriptor {
26
+ id: string;
27
+ name: string;
28
+ contextWindow?: number;
29
+ reasoningLevels: ReasoningEffort[];
30
+ defaultReasoningLevel?: ReasoningEffort;
31
+ }
32
+ interface GeminiModelListEntry {
33
+ name?: string;
34
+ displayName?: string;
35
+ inputTokenLimit?: number;
36
+ supportedGenerationMethods?: string[];
37
+ }
38
+ /**
39
+ * Fetch Google's model list and keep the newest general-purpose text models.
40
+ * Newly released Gemini versions appear without a catalog change; the static
41
+ * BUILTIN_MODELS entries stay as the offline/no-key fallback.
42
+ */
43
+ export declare function fetchGeminiModels(options: {
44
+ apiKey: string;
45
+ baseURL?: string;
46
+ fetch?: ProviderFetch;
47
+ limit?: number;
48
+ }): Promise<GeminiModelDescriptor[]>;
49
+ /**
50
+ * Ranking: one entry per (version, tier) family — GA ids beat dated previews —
51
+ * then newest version first, pro before flash before flash-lite, top N.
52
+ */
53
+ export declare function selectLatestGeminiModels(entries: GeminiModelListEntry[], limit?: number): GeminiModelDescriptor[];
54
+ /** Mirrors the static catalog's per-family thinking support. */
55
+ export declare function geminiReasoningLevels(modelId: string): ReasoningEffort[];
56
+ export {};