deepspace 0.4.3 → 0.4.5

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/worker.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as Y from 'yjs';
2
- import { LanguageModel, ModelMessage } from 'ai';
2
+ import { LanguageModel, ToolSet, ModelMessage } from 'ai';
3
3
  import * as better_auth from 'better-auth';
4
+ import { betterAuth } from 'better-auth';
4
5
  import * as better_auth_plugins from 'better-auth/plugins';
5
6
 
6
7
  /**
@@ -2507,6 +2508,30 @@ type ToolResult = {
2507
2508
  success: false;
2508
2509
  error: string;
2509
2510
  };
2511
+ /**
2512
+ * Page size the assistant defaults to for `records.query` when it omits
2513
+ * `limit`. Keeps a model-issued unbounded scan from blowing the tool-result
2514
+ * byte cap and gives the model a usable first page. Raise `limit` to page
2515
+ * through more (still subject to the cap; see
2516
+ * `DEFAULT_CONTEXT_CONFIG.toolResultCap` / `capToolResultSize`, which truncates
2517
+ * oversized pages gracefully rather than dropping them).
2518
+ *
2519
+ * Applied by the AI tool layer via `applyAiToolDefaults`, never by the shared
2520
+ * tools-api dispatch, so internal record readers (chat history, cron, app
2521
+ * `actions.query`) stay unbounded.
2522
+ */
2523
+ declare const DEFAULT_QUERY_LIMIT = 50;
2524
+ /**
2525
+ * Fill in assistant-only parameter defaults for a built-in tool call.
2526
+ *
2527
+ * Applied by the AI tool layer (`buildTools`) before a model-issued tool call
2528
+ * is dispatched, so the default only affects calls the assistant makes.
2529
+ * `records.query` doubles as the SDK's general record-read primitive (chat
2530
+ * history, cron, app `actions.query`); those callers reach the tools dispatch
2531
+ * directly and must return every row, so this default must not live in the
2532
+ * dispatch itself. Pure and non-mutating.
2533
+ */
2534
+ declare function applyAiToolDefaults(toolName: string, params: Record<string, unknown>): Record<string, unknown>;
2510
2535
  /**
2511
2536
  * Built-in tool definitions for storage, record, schema, user, and backup operations
2512
2537
  */
@@ -2804,7 +2829,7 @@ interface CronContext {
2804
2829
  };
2805
2830
  /**
2806
2831
  * Call a platform integration endpoint (e.g. "openai/chat-completion",
2807
- * "freepik/text-to-image-classic"). Billed to the app owner — the same
2832
+ * "fal/run-model"). Billed to the app owner using the same
2808
2833
  * APP_OWNER_JWT the rest of the SDK uses for server-side billed calls.
2809
2834
  */
2810
2835
  integrations: {
@@ -2903,6 +2928,49 @@ interface DeepSpaceAIOptions {
2903
2928
  */
2904
2929
  declare function createDeepSpaceAI(env: DeepSpaceAIEnv, provider: Provider, options?: DeepSpaceAIOptions): DeepSpaceModelFactory;
2905
2930
 
2931
+ /**
2932
+ * Composio tools for the Vercel AI SDK.
2933
+ *
2934
+ * Turns the platform's Composio integration into ready-to-use Vercel AI SDK
2935
+ * tools, so an agent (or the DeepSpace AI chat) can take actions on a user's
2936
+ * connected apps. Each returned tool's `execute()` calls our own
2937
+ * `composio/execute-tool` endpoint through the api-worker proxy, so our auth
2938
+ * and per-user billing apply. This is the managed-proxy equivalent of
2939
+ * Composio's `@composio/vercel` provider, which talks straight to Composio.
2940
+ *
2941
+ * `authToken` must be the END USER's JWT: Composio resolves the user's
2942
+ * connected accounts by the JWT subject, and that user is billed.
2943
+ *
2944
+ * Usage (inside a request handler, e.g. /api/ai/chat):
2945
+ *
2946
+ * import { composioTools, createDeepSpaceAI } from 'deepspace/worker'
2947
+ * const jwt = c.req.header('Authorization')!.slice(7)
2948
+ * const tools = await composioTools(c.env, { toolkit: 'gmail', authToken: jwt })
2949
+ * const ai = createDeepSpaceAI(c.env, 'anthropic', { authToken: jwt })
2950
+ * const result = streamText({ model: ai('claude-sonnet-4-6'), prompt, tools })
2951
+ *
2952
+ * Merge with your own tools: `tools: { ...buildTools(executor), ...composio }`.
2953
+ */
2954
+
2955
+ interface ComposioToolsOptions {
2956
+ /** End user's JWT. Required: the tools run as this user and bill them. */
2957
+ authToken: string;
2958
+ /** Restrict to one toolkit (e.g. 'gmail', 'github'). */
2959
+ toolkit?: string;
2960
+ /** Explicit tool slugs to expose (e.g. ['GMAIL_SEND_EMAIL']). */
2961
+ tools?: string[];
2962
+ /** Natural-language search to pick relevant tools. */
2963
+ search?: string;
2964
+ /** Cap how many tools are exposed (default 20). Keep small: the LLM sees them all. */
2965
+ limit?: number;
2966
+ }
2967
+ /**
2968
+ * Fetch Composio tools for the given scope and return them as a Vercel AI SDK
2969
+ * `ToolSet`. One `list-tools` call provides each tool's JSON Schema; each tool
2970
+ * executes via `composio/execute-tool` as the authenticated user.
2971
+ */
2972
+ declare function composioTools(env: ApiWorkerEnv, options: ComposioToolsOptions): Promise<ToolSet>;
2973
+
2906
2974
  /**
2907
2975
  * captureScreenshot — call platform-worker /internal/screenshot.
2908
2976
  *
@@ -2991,8 +3059,17 @@ declare function truncateOldToolResults(messages: ChatTurn[], keepRecent: number
2991
3059
  */
2992
3060
  declare function applySlidingWindow(messages: ChatTurn[], charCap: number, minKept: number): ChatTurn[];
2993
3061
  /**
2994
- * Replace oversized tool results with an error telling the agent to narrow
2995
- * its query. Keeps a small preview so the agent can see what it got.
3062
+ * Keep an individual tool result under `byteCap`.
3063
+ *
3064
+ * If the payload carries a list of items (e.g. a `records.query` result), it is
3065
+ * degraded gracefully: as many leading items as fit under the cap are returned,
3066
+ * the `success: true` shape is preserved, and `{ truncated, returned, total }`
3067
+ * flags are merged in next to the array so callers can still use the partial
3068
+ * data and paginate for the rest.
3069
+ *
3070
+ * Only when there is no array to trim (or even an empty list still overflows
3071
+ * because of oversized sibling fields) does it fall back to replacing the
3072
+ * result with an error + small preview telling the agent to narrow its query.
2996
3073
  */
2997
3074
  declare function capToolResultSize(result: unknown, byteCap: number): unknown;
2998
3075
  /**
@@ -3421,11 +3498,6 @@ declare function timingSafeEqualHex(a: string, b: string): Promise<boolean>;
3421
3498
 
3422
3499
  declare function decodeJwtPayload(token: string | null | undefined): TokenDebugInfo | undefined;
3423
3500
 
3424
- /**
3425
- * Better Auth configuration factory for DeepSpace
3426
- *
3427
- * Provides pre-configured Better Auth instances for Cloudflare Workers + D1.
3428
- */
3429
3501
  interface DeepSpaceAuthConfig {
3430
3502
  /** D1 database binding */
3431
3503
  database: D1Database;
@@ -3443,29 +3515,28 @@ interface DeepSpaceAuthConfig {
3443
3515
  clientId: string;
3444
3516
  clientSecret: string;
3445
3517
  };
3518
+ /** Microsoft (Entra ID) OAuth credentials (optional) */
3519
+ microsoft?: {
3520
+ clientId: string;
3521
+ clientSecret: string;
3522
+ };
3523
+ /**
3524
+ * Apple (Sign in with Apple) credentials (optional). Pass the raw
3525
+ * Sign-in-with-Apple key material; the ES256 client-secret JWT is minted
3526
+ * on demand, so there is no six-month token to rotate by hand.
3527
+ */
3528
+ apple?: {
3529
+ clientId: string;
3530
+ teamId: string;
3531
+ keyId: string;
3532
+ privateKey: string;
3533
+ };
3446
3534
  /** Enable email/password authentication */
3447
3535
  emailAndPassword?: boolean;
3448
3536
  /** Trusted origins for CORS */
3449
3537
  trustedOrigins?: string[];
3450
3538
  }
3451
- /**
3452
- * Create a Better Auth instance configured for DeepSpace.
3453
- *
3454
- * This is called per-request in the auth worker since D1 bindings
3455
- * are request-scoped in Cloudflare Workers.
3456
- */
3457
3539
  declare function createDeepSpaceAuth(config: DeepSpaceAuthConfig): better_auth.Auth<{
3458
- database: D1Database;
3459
- baseURL: string;
3460
- secret: string;
3461
- emailAndPassword: {
3462
- enabled: boolean;
3463
- };
3464
- socialProviders: Record<string, {
3465
- clientId: string;
3466
- clientSecret: string;
3467
- }>;
3468
- trustedOrigins: string[];
3469
3540
  plugins: [{
3470
3541
  id: "organization";
3471
3542
  endpoints: better_auth_plugins.OrganizationEndpoints<better_auth_plugins.OrganizationOptions & {
@@ -4265,6 +4336,30 @@ declare function createDeepSpaceAuth(config: DeepSpaceAuthConfig): better_auth.A
4265
4336
  INVALID_TWO_FACTOR_COOKIE: better_auth.RawError<"INVALID_TWO_FACTOR_COOKIE">;
4266
4337
  };
4267
4338
  }];
4339
+ advanced?: {
4340
+ cookies: {
4341
+ state: {
4342
+ attributes: {
4343
+ sameSite: "none";
4344
+ secure: true;
4345
+ };
4346
+ };
4347
+ oauth_state: {
4348
+ attributes: {
4349
+ sameSite: "none";
4350
+ secure: true;
4351
+ };
4352
+ };
4353
+ };
4354
+ } | undefined;
4355
+ database: D1Database;
4356
+ baseURL: string;
4357
+ secret: string;
4358
+ emailAndPassword: {
4359
+ enabled: boolean;
4360
+ };
4361
+ socialProviders: Parameters<typeof betterAuth>[0]["socialProviders"];
4362
+ trustedOrigins: string[];
4268
4363
  }>;
4269
4364
  type DeepSpaceAuth = ReturnType<typeof createDeepSpaceAuth>;
4270
4365
 
@@ -4275,4 +4370,4 @@ type DeepSpaceAuth = ReturnType<typeof createDeepSpaceAuth>;
4275
4370
  /** Collections that bypass schema checks (permissive access) */
4276
4371
  declare const SYSTEM_COLLECTIONS: Set<string>;
4277
4372
 
4278
- export { AI_CHATS_SCHEMA, AI_MESSAGES_SCHEMA, ALLOWED_BINDING_TYPES, APP_NAME_RULES, AUTO_PROVISIONABLE_TYPES, AUTO_PROVISION_SENTINEL, type ActionContext, type ActionHandler, type ActionResult, type ActionTools, type ApiWorkerEnv, type AppNameResolution, type AppNameValidation, type AuthWorkerEnv, Awareness, type AwarenessState, type AwarenessStates, BASE_USERS_SCHEMA, BUILT_IN_TOOLS, type BaseMessage, BaseRoom, CHANNELS_SCHEMA, CHANNEL_INVITATIONS_SCHEMA, CHANNEL_MEMBERS_SCHEMA, CONVERSATION_SCHEMAS, COST_RATES, CanvasRoom, type CanvasShape, type ChatContextConfig, type ChatMessageRow, type ChatRow, type ChatTurn, type ClientMessage, type CollectionPermissionSummary, type CollectionSchema, type ColumnDefinition, type ColumnInterpretation, type ConnectionAttachment, type ConvMemberData, type ConvMessageData, type ConvReactionData, type ConvReadCursorData, type ConvVoteData, type ConversationStateData, type CronContext, type CronExecution, CronRoom, type CronRoomConfig, type CronTask, type CustomBinding, type CustomBindingManifest, DEFAULT_CONTEXT_CONFIG, DEFAULT_DO_MANIFEST, DIRECTORY_SCHEMAS, type DOBindings, type DOManifest, type DOManifestEntry, type DeepSpaceAIEnv, type DeepSpaceAIOptions, type DeepSpaceAuth, type DeepSpaceAuthConfig, type DirectoryCommunityData, type DirectoryConversationData, type DirectoryMembershipData, type DirectoryPostData, type DoMigrationDirective, type DoMigrationPlan, type ExistingDOBinding, GLOBAL_DO_TYPES, GLOBAL_DO_TYPE_NAMES, type GameInput, GameRoom, type GameRoomConfig, type GetActionData, type GlobalDOType, type HandlerContext, type Job, type JobContext, JobRoom, type JobRoomConfig, type JobStatus, type JwtClaims, type JwtVerifierConfig, MESSAGES_SCHEMA, MSG, MSG_AWARENESS, MSG_SYNC, MSG_SYNC_STEP1, MSG_SYNC_STEP2, MSG_SYNC_UPDATE, MSG_YJS_AWARENESS, MSG_YJS_SYNC, type MessageHandlers, type MsgType, type MutateActionData, type PermissionAnalysis, type PermissionContext, type PermissionLevel, type PermissionSource, type PlatformWorkerEnv, type Player, type PrefixResult, type PresencePeer, PresenceRoom, type ProtocolMessage, type QueryActionData, REACTIONS_SCHEMA, READ_RECEIPTS_SCHEMA, RESERVED_BINDING_NAMES, RESERVED_COLLECTION_NAMES, ROLE_ADMIN, ROLE_ANONYMOUS, ROLE_DEFAULT, RecordRoom, type RecordRoomConfig, type ResolvedColumn, type ResolvedPermission, type RolePermissions, type RunMigrationsResult, SYSTEM_COLLECTIONS, SYSTEM_MANAGED_COLUMNS, SchemaRegistry, type ScopeContext, type ScopedR2Auth, type ScopedR2Config, type ScopedR2Handler, type ScreenshotEnv, type ScreenshotOptions, type ScreenshotResult, type ServerMessage, type SharedConnection, type StoredRecord, type Summarizer, type SyncResult, type TokenDebugInfo, type ToolResult, type ToolSchema, USERS_COLUMNS, type User, type UserAttachment, VOTING_SCHEMAS, type ValidationError, type VerifiedAuth, type VerifyOutcome, type VerifyResult, type Viewport, WORKSPACE_SCHEMAS, YjsRoom, analyzePermissions, apiWorkerFetch, appendMessage, applySlidingWindow, authWorkerFetch, bindingManifestFromOutputConfig, buildCronContext, buildTableSelect, buildUiParts, canCreate, canDelete, canRead, canUpdate, capToolResultSize, captureScreenshot, checkFieldPermissions, clientBuild, coerceValue, collectionTableName, columnId, computeDoMigration, computeHmacHex, createChat, createDecoder, createDeepSpaceAI, createDeepSpaceAuth, createEncoder, createScopedR2Handler, dataToColumnValues, decodeJwtPayload, deleteChatCascade, dispatch, encode, encodeAwarenessMessage, encodeSyncStep1, encodeSyncStep2, encodeUpdate, enqueueJob, getChat, getGlobalDOSchemas, getGlobalDOType, getMessageType, getRolePermissions, handleAwarenessMessage, handleSyncMessage, hasContent, isAutoProvision, isOwner, lintSchema, loadMessages, makeDefaultSummarizer, meterAi, meterUsage, meterVectorize, noopPermissionContext, platformWorkerFetch, prepareMessagesWithCompaction, priceBindingUsageEvent, readVarUint, readVarUint8Array, resolveAppName, resolveColumn, rowToData, runMigrations, serverBuild, timingSafeEqualHex, toUint8Array, totalChars, truncateOldToolResults, turnsToCoreMessages, unwrapToolOutput, updateChat, validateAppName, validateBindingManifest, validateDoManifest, verifyJwt, workspaceAccountsSchema, workspaceContentSharesSchema, workspaceEmailHandlesSchema, workspaceFormResponsesSchema, workspacePeopleSchema, workspaceProjectsSchema, workspaceTagsSchema, workspaceTasksSchema, workspaceTeamMembersSchema, workspaceTeamsSchema, workspaceTransactionsSchema, writeVarUint, writeVarUint8Array };
4373
+ export { AI_CHATS_SCHEMA, AI_MESSAGES_SCHEMA, ALLOWED_BINDING_TYPES, APP_NAME_RULES, AUTO_PROVISIONABLE_TYPES, AUTO_PROVISION_SENTINEL, type ActionContext, type ActionHandler, type ActionResult, type ActionTools, type ApiWorkerEnv, type AppNameResolution, type AppNameValidation, type AuthWorkerEnv, Awareness, type AwarenessState, type AwarenessStates, BASE_USERS_SCHEMA, BUILT_IN_TOOLS, type BaseMessage, BaseRoom, CHANNELS_SCHEMA, CHANNEL_INVITATIONS_SCHEMA, CHANNEL_MEMBERS_SCHEMA, CONVERSATION_SCHEMAS, COST_RATES, CanvasRoom, type CanvasShape, type ChatContextConfig, type ChatMessageRow, type ChatRow, type ChatTurn, type ClientMessage, type CollectionPermissionSummary, type CollectionSchema, type ColumnDefinition, type ColumnInterpretation, type ComposioToolsOptions, type ConnectionAttachment, type ConvMemberData, type ConvMessageData, type ConvReactionData, type ConvReadCursorData, type ConvVoteData, type ConversationStateData, type CronContext, type CronExecution, CronRoom, type CronRoomConfig, type CronTask, type CustomBinding, type CustomBindingManifest, DEFAULT_CONTEXT_CONFIG, DEFAULT_DO_MANIFEST, DEFAULT_QUERY_LIMIT, DIRECTORY_SCHEMAS, type DOBindings, type DOManifest, type DOManifestEntry, type DeepSpaceAIEnv, type DeepSpaceAIOptions, type DeepSpaceAuth, type DeepSpaceAuthConfig, type DirectoryCommunityData, type DirectoryConversationData, type DirectoryMembershipData, type DirectoryPostData, type DoMigrationDirective, type DoMigrationPlan, type ExistingDOBinding, GLOBAL_DO_TYPES, GLOBAL_DO_TYPE_NAMES, type GameInput, GameRoom, type GameRoomConfig, type GetActionData, type GlobalDOType, type HandlerContext, type Job, type JobContext, JobRoom, type JobRoomConfig, type JobStatus, type JwtClaims, type JwtVerifierConfig, MESSAGES_SCHEMA, MSG, MSG_AWARENESS, MSG_SYNC, MSG_SYNC_STEP1, MSG_SYNC_STEP2, MSG_SYNC_UPDATE, MSG_YJS_AWARENESS, MSG_YJS_SYNC, type MessageHandlers, type MsgType, type MutateActionData, type PermissionAnalysis, type PermissionContext, type PermissionLevel, type PermissionSource, type PlatformWorkerEnv, type Player, type PrefixResult, type PresencePeer, PresenceRoom, type ProtocolMessage, type QueryActionData, REACTIONS_SCHEMA, READ_RECEIPTS_SCHEMA, RESERVED_BINDING_NAMES, RESERVED_COLLECTION_NAMES, ROLE_ADMIN, ROLE_ANONYMOUS, ROLE_DEFAULT, RecordRoom, type RecordRoomConfig, type ResolvedColumn, type ResolvedPermission, type RolePermissions, type RunMigrationsResult, SYSTEM_COLLECTIONS, SYSTEM_MANAGED_COLUMNS, SchemaRegistry, type ScopeContext, type ScopedR2Auth, type ScopedR2Config, type ScopedR2Handler, type ScreenshotEnv, type ScreenshotOptions, type ScreenshotResult, type ServerMessage, type SharedConnection, type StoredRecord, type Summarizer, type SyncResult, type TokenDebugInfo, type ToolResult, type ToolSchema, USERS_COLUMNS, type User, type UserAttachment, VOTING_SCHEMAS, type ValidationError, type VerifiedAuth, type VerifyOutcome, type VerifyResult, type Viewport, WORKSPACE_SCHEMAS, YjsRoom, analyzePermissions, apiWorkerFetch, appendMessage, applyAiToolDefaults, applySlidingWindow, authWorkerFetch, bindingManifestFromOutputConfig, buildCronContext, buildTableSelect, buildUiParts, canCreate, canDelete, canRead, canUpdate, capToolResultSize, captureScreenshot, checkFieldPermissions, clientBuild, coerceValue, collectionTableName, columnId, composioTools, computeDoMigration, computeHmacHex, createChat, createDecoder, createDeepSpaceAI, createDeepSpaceAuth, createEncoder, createScopedR2Handler, dataToColumnValues, decodeJwtPayload, deleteChatCascade, dispatch, encode, encodeAwarenessMessage, encodeSyncStep1, encodeSyncStep2, encodeUpdate, enqueueJob, getChat, getGlobalDOSchemas, getGlobalDOType, getMessageType, getRolePermissions, handleAwarenessMessage, handleSyncMessage, hasContent, isAutoProvision, isOwner, lintSchema, loadMessages, makeDefaultSummarizer, meterAi, meterUsage, meterVectorize, noopPermissionContext, platformWorkerFetch, prepareMessagesWithCompaction, priceBindingUsageEvent, readVarUint, readVarUint8Array, resolveAppName, resolveColumn, rowToData, runMigrations, serverBuild, timingSafeEqualHex, toUint8Array, totalChars, truncateOldToolResults, turnsToCoreMessages, unwrapToolOutput, updateChat, validateAppName, validateBindingManifest, validateDoManifest, verifyJwt, workspaceAccountsSchema, workspaceContentSharesSchema, workspaceEmailHandlesSchema, workspaceFormResponsesSchema, workspacePeopleSchema, workspaceProjectsSchema, workspaceTagsSchema, workspaceTasksSchema, workspaceTeamMembersSchema, workspaceTeamsSchema, workspaceTransactionsSchema, writeVarUint, writeVarUint8Array };
package/dist/worker.js CHANGED
@@ -1952,17 +1952,24 @@ async function handleSetRole(ctx, ws, attachment, payload) {
1952
1952
  import * as Y3 from "yjs";
1953
1953
 
1954
1954
  // src/server/utils/tools.ts
1955
+ var DEFAULT_QUERY_LIMIT = 50;
1956
+ function applyAiToolDefaults(toolName, params) {
1957
+ if (toolName === "records.query" && params.limit === void 0) {
1958
+ return { ...params, limit: DEFAULT_QUERY_LIMIT };
1959
+ }
1960
+ return params;
1961
+ }
1955
1962
  var BUILT_IN_TOOLS = [
1956
1963
  // Record tools (structured collections with RBAC)
1957
1964
  {
1958
1965
  name: "records.query",
1959
- description: "Query records from a collection with optional filtering, ordering, and limits",
1966
+ description: `Query records from a collection with optional filtering, ordering, and pagination. Returns at most \`limit\` records (default ${DEFAULT_QUERY_LIMIT}). Large result sets are capped at ~30KB: an oversized page is truncated to the leading records that fit and flagged with \`{ truncated, returned, total }\`, so narrow with a \`where\` filter (or page via \`orderBy\` + \`limit\`) to see the rest.`,
1960
1967
  params: {
1961
1968
  collection: { type: "string", description: "Collection name to query", required: true },
1962
1969
  where: { type: "object", description: "Filter object with field=value equality conditions", required: false },
1963
1970
  orderBy: { type: "string", description: 'Field to order by (or "createdAt"/"updatedAt")', required: false },
1964
1971
  orderDir: { type: "string", description: 'Order direction: "asc" or "desc" (default: "desc")', required: false },
1965
- limit: { type: "number", description: "Maximum number of records to return", required: false }
1972
+ limit: { type: "number", description: `Maximum number of records to return (default: ${DEFAULT_QUERY_LIMIT}). Oversized pages are still capped at ~30KB and truncated with returned/total flags.`, required: false }
1966
1973
  }
1967
1974
  },
1968
1975
  {
@@ -2132,11 +2139,11 @@ async function handleToolsRequest(ctx, request, path) {
2132
2139
  }
2133
2140
  if (path.startsWith("tools/describe/")) {
2134
2141
  const toolName = path.replace("tools/describe/", "");
2135
- const tool = BUILT_IN_TOOLS.find((t) => t.name === toolName);
2136
- if (!tool) {
2142
+ const tool2 = BUILT_IN_TOOLS.find((t) => t.name === toolName);
2143
+ if (!tool2) {
2137
2144
  return Response.json({ error: `Tool not found: ${toolName}` }, { status: 404, headers: CORS_HEADERS });
2138
2145
  }
2139
- return Response.json({ tool }, { headers: CORS_HEADERS });
2146
+ return Response.json({ tool: tool2 }, { headers: CORS_HEADERS });
2140
2147
  }
2141
2148
  if (path.startsWith("tools/execute") && request.method === "POST") {
2142
2149
  return handleToolExecute(ctx, request);
@@ -2153,8 +2160,8 @@ async function handleToolExecute(ctx, request) {
2153
2160
  { status: 400, headers: CORS_HEADERS }
2154
2161
  );
2155
2162
  }
2156
- const { tool, params = {} } = body;
2157
- if (!tool) {
2163
+ const { tool: tool2, params = {} } = body;
2164
+ if (!tool2) {
2158
2165
  return Response.json(
2159
2166
  { success: false, error: 'Missing "tool" in request body' },
2160
2167
  { status: 400, headers: CORS_HEADERS }
@@ -2171,8 +2178,8 @@ async function handleToolExecute(ctx, request) {
2171
2178
  userRole = user.role;
2172
2179
  }
2173
2180
  }
2174
- if (tool.startsWith("yjs.")) {
2175
- const result2 = await executeYjsTool(ctx, tool, params, userId, userRole);
2181
+ if (tool2.startsWith("yjs.")) {
2182
+ const result2 = await executeYjsTool(ctx, tool2, params, userId, userRole);
2176
2183
  const status2 = result2.success ? 200 : result2.error?.includes("not found") ? 404 : 400;
2177
2184
  return Response.json(result2, { status: status2, headers: CORS_HEADERS });
2178
2185
  }
@@ -2183,7 +2190,7 @@ async function handleToolExecute(ctx, request) {
2183
2190
  getPermissionContext: ctx.getPermissionContext,
2184
2191
  send: ctx.send
2185
2192
  };
2186
- const result = await executeTool(recordCtx, tool, params, userId, userRole, isAppAction);
2193
+ const result = await executeTool(recordCtx, tool2, params, userId, userRole, isAppAction);
2187
2194
  const status = result.success ? 200 : result.error?.includes("not found") ? 404 : 400;
2188
2195
  return Response.json(result, { status, headers: CORS_HEADERS });
2189
2196
  }
@@ -6110,7 +6117,7 @@ function authWorkerFetch(env, path, init) {
6110
6117
  function buildCronContext(env, ownerUserId, roomId = "default") {
6111
6118
  const roomIdObj = env.RECORD_ROOMS.idFromName(roomId);
6112
6119
  const room = env.RECORD_ROOMS.get(roomIdObj);
6113
- async function executeTool3(tool, params) {
6120
+ async function executeTool3(tool2, params) {
6114
6121
  const response = await room.fetch(new Request("https://internal/api/tools/execute", {
6115
6122
  method: "POST",
6116
6123
  headers: {
@@ -6118,11 +6125,11 @@ function buildCronContext(env, ownerUserId, roomId = "default") {
6118
6125
  "X-User-Id": ownerUserId,
6119
6126
  "X-App-Action": "true"
6120
6127
  },
6121
- body: JSON.stringify({ tool, params })
6128
+ body: JSON.stringify({ tool: tool2, params })
6122
6129
  }));
6123
6130
  const result = await response.json();
6124
6131
  if (!result.success) {
6125
- throw new Error(`RecordRoom tool ${tool} failed: ${result.error || "Unknown error"}`);
6132
+ throw new Error(`RecordRoom tool ${tool2} failed: ${result.error || "Unknown error"}`);
6126
6133
  }
6127
6134
  return result.data;
6128
6135
  }
@@ -6243,6 +6250,87 @@ function createDeepSpaceAI(env, provider, options = {}) {
6243
6250
  }
6244
6251
  }
6245
6252
 
6253
+ // src/server/utils/composio-tools.ts
6254
+ import { tool, jsonSchema } from "ai";
6255
+ var EMPTY_SCHEMA = { type: "object", properties: {} };
6256
+ async function requestComposio(env, endpoint, params, authToken) {
6257
+ const res = await apiWorkerFetch(env, `/api/integrations/composio/${endpoint}`, {
6258
+ method: "POST",
6259
+ headers: {
6260
+ "Content-Type": "application/json",
6261
+ Authorization: `Bearer ${authToken}`
6262
+ },
6263
+ body: JSON.stringify(params)
6264
+ });
6265
+ const text = await res.text();
6266
+ let parsed = {};
6267
+ try {
6268
+ parsed = text ? JSON.parse(text) : {};
6269
+ } catch {
6270
+ }
6271
+ const detail = parsed.message || parsed.error || text || `HTTP ${res.status}`;
6272
+ return { ok: res.ok, success: parsed.success === true, data: parsed.data, detail };
6273
+ }
6274
+ function toolKey(slug) {
6275
+ const key = slug.replace(/[^a-zA-Z0-9_-]/g, "_");
6276
+ return key.length <= 64 ? key : key.slice(0, 64);
6277
+ }
6278
+ async function composioTools(env, options) {
6279
+ const { authToken } = options;
6280
+ if (!authToken) {
6281
+ throw new Error(
6282
+ "composioTools: options.authToken is required. Pass the end user's JWT so the tools run as that user (Composio resolves their connected accounts by it) and the calls are billed to them."
6283
+ );
6284
+ }
6285
+ const list = await requestComposio(
6286
+ env,
6287
+ "list-tools",
6288
+ {
6289
+ toolkit: options.toolkit,
6290
+ toolSlugs: options.tools?.length ? options.tools.join(",") : void 0,
6291
+ search: options.search,
6292
+ limit: options.limit ?? 20
6293
+ },
6294
+ authToken
6295
+ );
6296
+ if (!list.ok || !list.success) {
6297
+ throw new Error(`composioTools: failed to list Composio tools: ${list.detail}`);
6298
+ }
6299
+ const items = Array.isArray(list.data?.items) ? list.data.items : [];
6300
+ const tools = {};
6301
+ for (const item of items) {
6302
+ if (!item?.slug) continue;
6303
+ const slug = item.slug;
6304
+ const schema = item.input_parameters ?? EMPTY_SCHEMA;
6305
+ tools[toolKey(slug)] = tool({
6306
+ description: item.description ?? item.name ?? slug,
6307
+ inputSchema: jsonSchema(schema),
6308
+ execute: async (args) => {
6309
+ const r = await requestComposio(
6310
+ env,
6311
+ "execute-tool",
6312
+ { slug, arguments: args ?? {} },
6313
+ authToken
6314
+ );
6315
+ if (!r.ok || !r.success) {
6316
+ return { error: true, message: `Composio tool ${slug} failed: ${r.detail}` };
6317
+ }
6318
+ const data = r.data;
6319
+ if (data && typeof data === "object" && data.requiresConnection) {
6320
+ const toolkit = data.toolkit;
6321
+ return {
6322
+ requiresConnection: true,
6323
+ toolkit,
6324
+ message: `The user has not connected ${toolkit ?? "this app"}. Ask them to connect it before using this tool.`
6325
+ };
6326
+ }
6327
+ return data;
6328
+ }
6329
+ });
6330
+ }
6331
+ return tools;
6332
+ }
6333
+
6246
6334
  // src/server/utils/screenshot.ts
6247
6335
  async function captureScreenshot(env, opts) {
6248
6336
  const headers = new Headers({
@@ -6330,6 +6418,45 @@ function applySlidingWindow(messages, charCap, minKept) {
6330
6418
  }
6331
6419
  return out;
6332
6420
  }
6421
+ var TRIMMABLE_ARRAY_PATHS = [
6422
+ ["records"],
6423
+ ["data", "records"],
6424
+ ["items"],
6425
+ ["data", "items"],
6426
+ ["data"]
6427
+ ];
6428
+ function getPath(root, path) {
6429
+ let cur = root;
6430
+ for (const key of path) {
6431
+ if (!cur || typeof cur !== "object") return void 0;
6432
+ cur = cur[key];
6433
+ }
6434
+ return cur;
6435
+ }
6436
+ function setPath(root, path, value, flags) {
6437
+ const obj = root && typeof root === "object" ? root : {};
6438
+ const [head, ...tail] = path;
6439
+ if (tail.length === 0) {
6440
+ return { ...obj, [head]: value, ...flags };
6441
+ }
6442
+ return { ...obj, [head]: setPath(obj[head], tail, value, flags) };
6443
+ }
6444
+ function locateTrimmableArray(result) {
6445
+ for (const path of TRIMMABLE_ARRAY_PATHS) {
6446
+ const arr = getPath(result, path);
6447
+ if (Array.isArray(arr)) return { path, items: arr };
6448
+ }
6449
+ for (const [key, value] of Object.entries(result)) {
6450
+ if (Array.isArray(value)) return { path: [key], items: value };
6451
+ }
6452
+ const data = result.data;
6453
+ if (data && typeof data === "object") {
6454
+ for (const [key, value] of Object.entries(data)) {
6455
+ if (Array.isArray(value)) return { path: ["data", key], items: value };
6456
+ }
6457
+ }
6458
+ return void 0;
6459
+ }
6333
6460
  function capToolResultSize(result, byteCap) {
6334
6461
  let serialized;
6335
6462
  try {
@@ -6339,6 +6466,31 @@ function capToolResultSize(result, byteCap) {
6339
6466
  }
6340
6467
  if (typeof serialized !== "string") return result;
6341
6468
  if (serialized.length <= byteCap) return result;
6469
+ if (result && typeof result === "object") {
6470
+ const located = locateTrimmableArray(result);
6471
+ if (located) {
6472
+ const { path, items } = located;
6473
+ const total = items.length;
6474
+ const build = (k) => setPath(result, path, items.slice(0, k), { truncated: true, returned: k, total });
6475
+ const fits = (k) => {
6476
+ try {
6477
+ return JSON.stringify(build(k)).length <= byteCap;
6478
+ } catch {
6479
+ return false;
6480
+ }
6481
+ };
6482
+ if (fits(0)) {
6483
+ let lo = 0;
6484
+ let hi = total;
6485
+ while (lo < hi) {
6486
+ const mid = Math.ceil((lo + hi) / 2);
6487
+ if (fits(mid)) lo = mid;
6488
+ else hi = mid - 1;
6489
+ }
6490
+ if (lo > 0) return build(lo);
6491
+ }
6492
+ }
6493
+ }
6342
6494
  return {
6343
6495
  success: false,
6344
6496
  truncated: true,
@@ -6547,7 +6699,7 @@ function makeDefaultSummarizer(env, options = {}) {
6547
6699
  }
6548
6700
 
6549
6701
  // src/server/utils/chat-history.ts
6550
- async function executeTool2(stub, userId, tool, params) {
6702
+ async function executeTool2(stub, userId, tool2, params) {
6551
6703
  const res = await stub.fetch(new Request("https://internal/api/tools/execute", {
6552
6704
  method: "POST",
6553
6705
  headers: {
@@ -6555,11 +6707,11 @@ async function executeTool2(stub, userId, tool, params) {
6555
6707
  "X-User-Id": userId,
6556
6708
  "X-App-Action": "true"
6557
6709
  },
6558
- body: JSON.stringify({ tool, params })
6710
+ body: JSON.stringify({ tool: tool2, params })
6559
6711
  }));
6560
6712
  const body = await res.json();
6561
6713
  if (!body.success) {
6562
- throw new Error(`chat-history ${tool} failed: ${body.error ?? "unknown error"}`);
6714
+ throw new Error(`chat-history ${tool2} failed: ${body.error ?? "unknown error"}`);
6563
6715
  }
6564
6716
  return body.data;
6565
6717
  }
@@ -6956,6 +7108,7 @@ async function timingSafeEqualHex(a, b) {
6956
7108
  // src/server/auth/betterAuth.ts
6957
7109
  import { betterAuth } from "better-auth";
6958
7110
  import { organization, twoFactor } from "better-auth/plugins";
7111
+ import { SignJWT, importPKCS8 } from "jose";
6959
7112
  function createDeepSpaceAuth(config) {
6960
7113
  const socialProviders = {};
6961
7114
  if (config.google) {
@@ -6964,6 +7117,20 @@ function createDeepSpaceAuth(config) {
6964
7117
  if (config.github) {
6965
7118
  socialProviders.github = config.github;
6966
7119
  }
7120
+ if (config.microsoft) {
7121
+ socialProviders.microsoft = config.microsoft;
7122
+ }
7123
+ if (config.apple) {
7124
+ const apple = config.apple;
7125
+ socialProviders.apple = async () => {
7126
+ try {
7127
+ return { clientId: apple.clientId, clientSecret: await generateAppleClientSecret(apple) };
7128
+ } catch (err) {
7129
+ console.error("[deepspace] failed to mint Apple client secret; Apple sign-in disabled", err);
7130
+ return { clientId: apple.clientId, clientSecret: "" };
7131
+ }
7132
+ };
7133
+ }
6967
7134
  return betterAuth({
6968
7135
  database: config.database,
6969
7136
  baseURL: config.baseURL,
@@ -6976,11 +7143,42 @@ function createDeepSpaceAuth(config) {
6976
7143
  "https://deep.space",
6977
7144
  "https://*.deep.space",
6978
7145
  "https://*.app.space",
6979
- "http://localhost:*"
7146
+ "http://localhost:*",
7147
+ // Apple posts its OAuth callback from this origin (form_post).
7148
+ "https://appleid.apple.com"
6980
7149
  ],
7150
+ // Apple returns its callback as a cross-site form_post, which a
7151
+ // SameSite=Lax cookie won't ride along with — so the OAuth handshake
7152
+ // cookie must be SameSite=None. Scoped to just that cookie; the session
7153
+ // cookie stays Lax. Gated on Apple being configured: deployments without
7154
+ // Apple keep Lax entirely. Note that when Apple IS configured, this also
7155
+ // relaxes the handshake cookie for Google/GitHub/Microsoft on the same
7156
+ // instance — which is safe, since the state is encrypted and verified
7157
+ // independently of SameSite (plus a separate per-flow CSRF cookie).
7158
+ ...config.apple ? {
7159
+ advanced: {
7160
+ cookies: {
7161
+ state: { attributes: { sameSite: "none", secure: true } },
7162
+ oauth_state: { attributes: { sameSite: "none", secure: true } }
7163
+ }
7164
+ }
7165
+ } : {},
6981
7166
  plugins: [organization(), twoFactor()]
6982
7167
  });
6983
7168
  }
7169
+ var cachedAppleSecret = null;
7170
+ async function generateAppleClientSecret(apple) {
7171
+ const now = Math.floor(Date.now() / 1e3);
7172
+ if (cachedAppleSecret && cachedAppleSecret.keyId === apple.keyId && cachedAppleSecret.expiresAt - now > 3600) {
7173
+ return cachedAppleSecret.token;
7174
+ }
7175
+ const pem = apple.privateKey.replace(/\\n/g, "\n");
7176
+ const key = await importPKCS8(pem, "ES256");
7177
+ const expiresAt = now + 180 * 24 * 60 * 60;
7178
+ const token = await new SignJWT({}).setProtectedHeader({ alg: "ES256", kid: apple.keyId }).setIssuer(apple.teamId).setSubject(apple.clientId).setAudience("https://appleid.apple.com").setIssuedAt(now).setExpirationTime(expiresAt).sign(key);
7179
+ cachedAppleSecret = { keyId: apple.keyId, token, expiresAt };
7180
+ return token;
7181
+ }
6984
7182
  export {
6985
7183
  AI_CHATS_SCHEMA,
6986
7184
  AI_MESSAGES_SCHEMA,
@@ -7001,6 +7199,7 @@ export {
7001
7199
  CronRoom,
7002
7200
  DEFAULT_CONTEXT_CONFIG,
7003
7201
  DEFAULT_DO_MANIFEST,
7202
+ DEFAULT_QUERY_LIMIT,
7004
7203
  DIRECTORY_SCHEMAS,
7005
7204
  GLOBAL_DO_TYPES,
7006
7205
  GLOBAL_DO_TYPE_NAMES,
@@ -7034,6 +7233,7 @@ export {
7034
7233
  analyzePermissions,
7035
7234
  apiWorkerFetch,
7036
7235
  appendMessage,
7236
+ applyAiToolDefaults,
7037
7237
  applySlidingWindow,
7038
7238
  authWorkerFetch,
7039
7239
  bindingManifestFromOutputConfig,
@@ -7051,6 +7251,7 @@ export {
7051
7251
  coerceValue,
7052
7252
  collectionTableName,
7053
7253
  columnId,
7254
+ composioTools,
7054
7255
  computeDoMigration,
7055
7256
  computeHmacHex,
7056
7257
  createChat,