botinabox 2.10.1 → 2.12.0

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.
@@ -156,22 +156,30 @@ var GoogleCalendarConnector = class {
156
156
  errors
157
157
  };
158
158
  }
159
- /** Full sync using timeMin. */
159
+ /**
160
+ * Full sync — paginates through every event for the calendar to obtain a
161
+ * `nextSyncToken`. Google only emits `nextSyncToken` on the final page of a
162
+ * query that contains none of `timeMin`, `timeMax`, `orderBy`, `q`,
163
+ * `updatedMin`, `eventTypes`, `iCalUID`, `showDeleted`, or
164
+ * `showHiddenInvitations`. This implementation therefore omits all of those
165
+ * parameters and drains pagination to completion regardless of `options.limit`
166
+ * or `options.since` — a partial first sync would never mint a usable cursor,
167
+ * which would break every subsequent `syncIncremental` call.
168
+ *
169
+ * `options.limit` and `options.since` are intentionally ignored on full sync.
170
+ * Use `syncIncremental` (via `options.cursor`) for bounded follow-up syncs.
171
+ */
160
172
  async syncFull(options) {
161
173
  const calendarId = options?.filters?.calendarId ?? "primary";
162
174
  const records = [];
163
175
  const errors = [];
164
- const maxResults = options?.limit ?? 250;
165
- const timeMin = options?.since ? new Date(options.since).toISOString() : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3).toISOString();
166
176
  let pageToken;
167
177
  let nextSyncToken;
168
178
  do {
169
179
  const res = await this.calendar.events.list({
170
180
  calendarId,
171
- timeMin,
172
181
  singleEvents: true,
173
- orderBy: "startTime",
174
- maxResults: Math.min(maxResults - records.length, 250),
182
+ maxResults: 250,
175
183
  ...pageToken ? { pageToken } : {}
176
184
  });
177
185
  for (const event of res.data.items ?? []) {
@@ -180,15 +188,14 @@ var GoogleCalendarConnector = class {
180
188
  } catch (err) {
181
189
  errors.push({ id: event.id, error: errorMessage(err) });
182
190
  }
183
- if (records.length >= maxResults) break;
184
191
  }
185
192
  pageToken = res.data.nextPageToken ?? void 0;
186
193
  nextSyncToken = res.data.nextSyncToken ?? void 0;
187
- } while (pageToken && records.length < maxResults);
194
+ } while (pageToken);
188
195
  return {
189
196
  records,
190
197
  cursor: nextSyncToken,
191
- hasMore: !!pageToken,
198
+ hasMore: false,
192
199
  errors
193
200
  };
194
201
  }
@@ -98,6 +98,17 @@ export interface ExecutionEngineConfig {
98
98
  agent: Record<string, unknown>;
99
99
  task: Record<string, unknown>;
100
100
  }) => string | undefined;
101
+ /**
102
+ * Mark the system prompt as ephemerally cacheable. When true, the engine
103
+ * sends the system prompt as a single-element content block array with
104
+ * `cache_control: { type: 'ephemeral' }` instead of a plain string. This
105
+ * lets Anthropic's prompt-cache layer serve hits across calls within the
106
+ * 5-minute ephemeral TTL.
107
+ *
108
+ * Default: false (system prompt is sent as a plain string — unchanged
109
+ * behavior).
110
+ */
111
+ cacheSystemPrompt?: boolean;
101
112
  }
102
113
  /**
103
114
  * Wrap a set of context files in `<file path="...">...</file>` XML tags,
package/dist/index.js CHANGED
@@ -6627,11 +6627,18 @@ ${contextFilesBlock}` : "",
6627
6627
  let finalOutput = "";
6628
6628
  let totalInput = 0;
6629
6629
  let totalOutput = 0;
6630
+ const systemField = config.cacheSystemPrompt ? [
6631
+ {
6632
+ type: "text",
6633
+ text: systemPrompt,
6634
+ cache_control: { type: "ephemeral" }
6635
+ }
6636
+ ] : systemPrompt;
6630
6637
  for (let i = 0; i < maxIterations; i++) {
6631
6638
  const createParams = {
6632
6639
  model: taskModel,
6633
6640
  max_tokens: 4096,
6634
- system: systemPrompt,
6641
+ system: systemField,
6635
6642
  messages
6636
6643
  };
6637
6644
  if (toolDefs.length > 0) {
@@ -0,0 +1,89 @@
1
+ /** LLM provider types — Story 1.5 / 2.1 */
2
+ interface ToolDefinition {
3
+ name: string;
4
+ description: string;
5
+ parameters: Record<string, unknown>;
6
+ }
7
+ interface ChatMessage {
8
+ role: "user" | "assistant" | "system";
9
+ content: string | ContentBlock[];
10
+ }
11
+ type ContentBlock = {
12
+ type: "text";
13
+ text: string;
14
+ } | {
15
+ type: "tool_use";
16
+ id: string;
17
+ name: string;
18
+ input: unknown;
19
+ } | {
20
+ type: "tool_result";
21
+ tool_use_id: string;
22
+ content: string;
23
+ } | {
24
+ type: "image";
25
+ source: {
26
+ type: "base64";
27
+ media_type: string;
28
+ data: string;
29
+ };
30
+ } | {
31
+ type: "document";
32
+ source: {
33
+ type: "base64";
34
+ media_type: "application/pdf";
35
+ data: string;
36
+ };
37
+ };
38
+ interface ChatParams {
39
+ messages: ChatMessage[];
40
+ system?: string;
41
+ tools?: ToolDefinition[];
42
+ maxTokens?: number;
43
+ temperature?: number;
44
+ model: string;
45
+ abortSignal?: AbortSignal;
46
+ }
47
+ interface TokenUsage {
48
+ inputTokens: number;
49
+ outputTokens: number;
50
+ cacheReadTokens?: number;
51
+ cacheWriteTokens?: number;
52
+ }
53
+ interface ChatResult {
54
+ content: string;
55
+ toolUses?: ToolUse[];
56
+ usage: TokenUsage;
57
+ model: string;
58
+ stopReason: "end_turn" | "tool_use" | "max_tokens" | "stop_sequence";
59
+ }
60
+ interface ToolUse {
61
+ id: string;
62
+ name: string;
63
+ input: unknown;
64
+ }
65
+ interface ModelInfo {
66
+ id: string;
67
+ displayName: string;
68
+ contextWindow: number;
69
+ maxOutputTokens: number;
70
+ capabilities: Array<"chat" | "tools" | "vision" | "streaming">;
71
+ /** Cost in micro-cents per 1M tokens */
72
+ inputCostPerMToken?: number;
73
+ outputCostPerMToken?: number;
74
+ }
75
+ interface ResolvedModel {
76
+ provider: string;
77
+ model: string;
78
+ }
79
+ interface LLMProvider {
80
+ id: string;
81
+ displayName: string;
82
+ models: ModelInfo[];
83
+ chat(params: ChatParams): Promise<ChatResult>;
84
+ chatStream(params: ChatParams): AsyncGenerator<string, ChatResult, unknown>;
85
+ /** Convert ToolDefinition[] to provider-native format */
86
+ serializeTools(tools: ToolDefinition[]): unknown;
87
+ }
88
+
89
+ export type { ChatMessage as C, LLMProvider as L, ModelInfo as M, ResolvedModel as R, TokenUsage as T, ChatParams as a, ChatResult as b, ContentBlock as c, ToolUse as d, ToolDefinition as e };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botinabox",
3
- "version": "2.10.1",
3
+ "version": "2.12.0",
4
4
  "description": "Bot in a Box — framework for building multi-agent bots",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",