@composio/experimental 0.2.3-beta.0 → 0.2.3-beta.1

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.
@@ -1,5 +1,6 @@
1
1
  import { BaseAgenticProvider, ExecuteToolFn, McpServerGetResponse, McpUrlResponse, Tool, ToolExecuteResponse } from "@composio/core";
2
- import { ApprovalContext, DynamicResolveContext, ToolContext, ToolDefinition } from "eve/tools";
2
+ import { DynamicResolveContext, ToolContext, ToolDefinition } from "eve/tools";
3
+ import { ApprovalContext } from "eve/tools/approval";
3
4
  //#region src/eve/hooks.d.ts
4
5
  type MaybePromise<T> = T | Promise<T>;
5
6
  type Next = () => Promise<ToolExecuteResponse>;
@@ -34,26 +35,27 @@ interface EveProviderHooks {
34
35
  remoteBash?: EveHook;
35
36
  onAuthLink?: EveAuthLinkHook;
36
37
  }
37
- declare const denyEveToolCall: (reason: string) => ToolExecuteResponse;
38
+ export declare const denyEveToolCall: (reason: string) => ToolExecuteResponse;
38
39
  //#endregion
39
40
  //#region src/eve/provider.d.ts
40
41
  type EveTool = ToolDefinition<Record<string, unknown>, ToolExecuteResponse>;
41
42
  type EveToolCollection = Record<string, EveTool>;
42
43
  type EveNeedsApproval = (tool: Tool, context: ApprovalContext<Record<string, unknown>>) => boolean;
43
44
  /** Require approval for direct calls and matching entries inside a multi-execute call. */
44
- declare const requireApprovalForTools: (...toolSlugs: string[]) => EveNeedsApproval;
45
+ export declare const requireApprovalForTools: (...toolSlugs: string[]) => EveNeedsApproval;
45
46
  interface EveProviderOptions {
46
47
  strict?: boolean;
47
48
  hooks?: EveProviderHooks;
48
49
  needsApproval?: EveNeedsApproval;
49
50
  }
50
- declare class EveProvider extends BaseAgenticProvider<EveToolCollection, EveTool, McpServerGetResponse> {
51
+ export declare class EveProvider extends BaseAgenticProvider<EveToolCollection, EveTool, McpServerGetResponse> {
51
52
  private readonly options;
52
53
  readonly name = "eve";
53
54
  constructor(options?: EveProviderOptions);
54
55
  wrapTool(tool: Tool, executeTool: ExecuteToolFn): EveTool;
55
56
  wrapTools(tools: Tool[], executeTool: ExecuteToolFn): EveToolCollection;
56
57
  wrapMcpServerResponse(data: McpUrlResponse): McpServerGetResponse;
58
+ private defineBoundTool;
57
59
  }
58
60
  //#endregion
59
61
  //#region src/eve/resolver.d.ts
@@ -61,6 +63,6 @@ type EveSession = {
61
63
  tools: () => Promise<EveToolCollection>;
62
64
  };
63
65
  type EveSessionSource<S extends EveSession> = S | Promise<S> | ((context: DynamicResolveContext) => S | Promise<S>);
64
- declare function defineComposioTools<S extends EveSession>(source: EveSessionSource<S>): import("eve/tools").DynamicSentinel<EveToolCollection>;
66
+ export declare function defineComposioTools<S extends EveSession>(source: EveSessionSource<S>): import("eve/connections").DynamicSentinel<EveToolCollection>;
65
67
  //#endregion
66
- export { type EveAuthLinkContext, type EveAuthLinkHook, type EveHook, type EveHookContext, type EveHookControls, type EveNeedsApproval, EveProvider, type EveProviderHooks, type EveProviderOptions, type EveTool, type EveToolCollection, defineComposioTools, denyEveToolCall, requireApprovalForTools };
68
+ export type { EveAuthLinkContext, EveAuthLinkHook, EveHook, EveHookContext, EveHookControls, EveNeedsApproval, EveProviderHooks, EveProviderOptions, EveTool, EveToolCollection };
@@ -2,6 +2,39 @@ import { t as extractComposioConnectLinks } from "../auth-links-BsKdD1dc.mjs";
2
2
  import { BaseAgenticProvider, normalizeToolArguments, removeNonRequiredProperties } from "@composio/core";
3
3
  import { defineDynamic, defineTool } from "eve/tools";
4
4
 
5
+ //#region src/eve/durable.ts
6
+ /**
7
+ * eve rejects a dynamic tool whose callbacks carry no durable descriptor: each
8
+ * callback must be a JSON-serializable closure plus a function that takes that
9
+ * closure as its first argument, so a parked or replayed call can be rebuilt
10
+ * after the process that resolved it is gone. eve's build transform stamps the
11
+ * descriptor onto `defineTool` calls it finds in the agent's own source, and it
12
+ * never runs on this package inside `node_modules` — so the provider stamps its
13
+ * own descriptors here.
14
+ *
15
+ * The descriptor key is a global-registry symbol, the same identity eve's
16
+ * runtime reads, so no eve internal has to be imported.
17
+ */
18
+ const DURABLE_CALLBACK = Symbol.for("eve:durable-dynamic-callback");
19
+ /**
20
+ * Binds `callback` to `closure` and stamps eve's durable descriptor on the
21
+ * result. eve registers the callback under the tool's name at resolve time,
22
+ * persists only `closure`, and calls `callback(closure, ...args)` on replay;
23
+ * direct callers get the ordinary `(...args)` signature.
24
+ */
25
+ function withDurableClosure(closure, callback) {
26
+ const live = (...args) => callback(closure, ...args);
27
+ Object.defineProperty(live, DURABLE_CALLBACK, {
28
+ configurable: true,
29
+ value: {
30
+ callback,
31
+ closure
32
+ }
33
+ });
34
+ return live;
35
+ }
36
+
37
+ //#endregion
5
38
  //#region src/eve/hooks.ts
6
39
  const denyEveToolCall = (reason) => ({
7
40
  data: {},
@@ -83,10 +116,6 @@ const toEveInputSchema = (tool, strict) => {
83
116
  properties: { ...params.properties }
84
117
  });
85
118
  };
86
- const toEveApprovalPolicy = (tool, approvalPolicy) => {
87
- if (!approvalPolicy) return void 0;
88
- return (context) => approvalPolicy(tool, context);
89
- };
90
119
  const isProtectedToolItem = (item, protectedSlugs) => {
91
120
  if (typeof item !== "object" || item === null) return false;
92
121
  const toolSlug = item.tool_slug;
@@ -105,6 +134,43 @@ const requireApprovalForTools = (...toolSlugs) => {
105
134
  return requestedTools.some((item) => isProtectedToolItem(item, protectedSlugs));
106
135
  };
107
136
  };
137
+ /**
138
+ * Bindings for every resolve in this process, keyed by the id stamped into the
139
+ * closure. `executeTool` is bound to one Composio session, so a closure must
140
+ * name the resolve that produced it rather than just the slug: sessions for
141
+ * different users share one provider and would otherwise cross-execute. The
142
+ * map is module-level because eve's callback registry is keyed by tool name
143
+ * only, so a second `EveProvider` in the process replays through the same
144
+ * callbacks. Entries live as long as the process; eve can resume a parked
145
+ * call at any time. Ids carry a per-process token so a closure persisted by
146
+ * an earlier process fails the lookup instead of matching whichever resolve
147
+ * reused its counter value.
148
+ */
149
+ const bindings = /* @__PURE__ */ new Map();
150
+ const processToken = globalThis.crypto.randomUUID();
151
+ let nextBindingId = 0;
152
+ const bind = (binding) => {
153
+ const id = `${processToken}:${++nextBindingId}`;
154
+ bindings.set(id, binding);
155
+ return id;
156
+ };
157
+ const requireBinding = ({ slug, binding }) => {
158
+ const bound = bindings.get(binding);
159
+ const tool = bound?.tools.get(slug);
160
+ if (!bound || !tool) throw new Error(`Composio tool "${slug}" has no executor in this process. Resolve the session's tools again before calling it.`);
161
+ return {
162
+ ...bound,
163
+ tool
164
+ };
165
+ };
166
+ const execute = async (closure, input, context) => {
167
+ const { executeTool, options } = requireBinding(closure);
168
+ return applyHooks(options.hooks ?? {}, closure.slug, normalizeToolArguments(input, closure.slug), executeTool, context);
169
+ };
170
+ const approve = (closure, context) => {
171
+ const { tool, options } = requireBinding(closure);
172
+ return options.needsApproval(tool, context);
173
+ };
108
174
  var EveProvider = class extends BaseAgenticProvider {
109
175
  options;
110
176
  name = "eve";
@@ -113,17 +179,15 @@ var EveProvider = class extends BaseAgenticProvider {
113
179
  this.options = options;
114
180
  }
115
181
  wrapTool(tool, executeTool) {
116
- const inputSchema = toEveInputSchema(tool, this.options.strict);
117
- const approval = toEveApprovalPolicy(tool, this.options.needsApproval);
118
- return defineTool({
119
- description: tool.description ?? tool.name,
120
- inputSchema,
121
- approval,
122
- execute: (input, context) => applyHooks(this.options.hooks ?? {}, tool.slug, normalizeToolArguments(input, tool.slug), executeTool, context)
123
- });
182
+ return this.wrapTools([tool], executeTool)[tool.slug];
124
183
  }
125
184
  wrapTools(tools, executeTool) {
126
- return Object.fromEntries(tools.map((tool) => [tool.slug, this.wrapTool(tool, executeTool)]));
185
+ const binding = bind({
186
+ tools: new Map(tools.map((tool) => [tool.slug, tool])),
187
+ executeTool,
188
+ options: this.options
189
+ });
190
+ return Object.fromEntries(tools.map((tool) => [tool.slug, this.defineBoundTool(tool, binding)]));
127
191
  }
128
192
  wrapMcpServerResponse(data) {
129
193
  return data.map((item) => ({
@@ -131,6 +195,18 @@ var EveProvider = class extends BaseAgenticProvider {
131
195
  name: item.name
132
196
  }));
133
197
  }
198
+ defineBoundTool(tool, binding) {
199
+ const closure = {
200
+ slug: tool.slug,
201
+ binding
202
+ };
203
+ return defineTool({
204
+ description: tool.description ?? tool.name,
205
+ inputSchema: toEveInputSchema(tool, this.options.strict),
206
+ approval: this.options.needsApproval ? withDurableClosure(closure, approve) : void 0,
207
+ execute: withDurableClosure(closure, execute)
208
+ });
209
+ }
134
210
  };
135
211
 
136
212
  //#endregion
package/dist/index.d.mts CHANGED
@@ -228,13 +228,13 @@ type PiConnectionManagementResult<TState = unknown, TAuthorizeResult = unknown>
228
228
  };
229
229
  //#endregion
230
230
  //#region src/auth-links.d.ts
231
- declare const extractComposioConnectLinks: (value: unknown) => string[];
231
+ export declare const extractComposioConnectLinks: (value: unknown) => string[];
232
232
  //#endregion
233
233
  //#region src/pi/provider.d.ts
234
234
  /**
235
235
  * Provider for integrating Composio tools with Pi SDK custom tools.
236
236
  */
237
- declare class PiProvider extends BaseAgenticProvider<PiToolCollection, PiTool, McpServerGetResponse> {
237
+ export declare class PiProvider extends BaseAgenticProvider<PiToolCollection, PiTool, McpServerGetResponse> {
238
238
  private readonly options;
239
239
  readonly name = "pi";
240
240
  constructor(options?: PiProviderOptions);
@@ -255,11 +255,11 @@ declare class PiProvider extends BaseAgenticProvider<PiToolCollection, PiTool, M
255
255
  }
256
256
  //#endregion
257
257
  //#region src/pi/prompt.d.ts
258
- declare const createPiComposioSystemPrompt: (sessionId?: string, options?: {
258
+ export declare const createPiComposioSystemPrompt: (sessionId?: string, options?: {
259
259
  includeWorkbenchTools?: boolean;
260
260
  }) => string;
261
261
  //#endregion
262
262
  //#region src/pi/results.d.ts
263
- declare const denyPiToolCall: (error: string) => PiDeniedResult;
263
+ export declare const denyPiToolCall: (error: string) => PiDeniedResult;
264
264
  //#endregion
265
- export { type MaybePromise, DEFAULT_SESSION_TOOL_NAMES as PI_COMPOSIO_SESSION_TOOL_NAMES, type PiAuthLinkContext, type PiAuthorizeToolkitOptions, type PiBaseToolContext, type PiComposioSessionLike, type PiConnectionHandlers, type PiConnectionManagementContext, type PiConnectionManagementResult, type PiConnectionToolkitResult, type PiDeniedResult, type PiExecutableSessionLike, type PiExecuteContext, type PiExecuteHandler, type PiExecuteHookContext, type PiHookControls, type PiHookNext, type PiManageConnectionsHookContext, PiProvider, type PiProviderOptions, type PiRemoteBashHookContext, type PiRemoteBashRequest, type PiRemoteWorkbenchHookContext, type PiRemoteWorkbenchRequest, type PiSearchContext, type PiSearchHandler, type PiSearchHookContext, type PiSessionHooks, type PiSessionToolCapabilities, type PiSessionToolName, type PiSessionToolOptions, type PiTool, type PiToolCollection, type PiToolDetails, type PiToolResultFormatter, createPiComposioSystemPrompt, denyPiToolCall, extractComposioConnectLinks };
265
+ export { type MaybePromise, DEFAULT_SESSION_TOOL_NAMES as PI_COMPOSIO_SESSION_TOOL_NAMES, type PiAuthLinkContext, type PiAuthorizeToolkitOptions, type PiBaseToolContext, type PiComposioSessionLike, type PiConnectionHandlers, type PiConnectionManagementContext, type PiConnectionManagementResult, type PiConnectionToolkitResult, type PiDeniedResult, type PiExecutableSessionLike, type PiExecuteContext, type PiExecuteHandler, type PiExecuteHookContext, type PiHookControls, type PiHookNext, type PiManageConnectionsHookContext, type PiProviderOptions, type PiRemoteBashHookContext, type PiRemoteBashRequest, type PiRemoteWorkbenchHookContext, type PiRemoteWorkbenchRequest, type PiSearchContext, type PiSearchHandler, type PiSearchHookContext, type PiSessionHooks, type PiSessionToolCapabilities, type PiSessionToolName, type PiSessionToolOptions, type PiTool, type PiToolCollection, type PiToolDetails, type PiToolResultFormatter };
package/dist/index.mjs CHANGED
@@ -255,7 +255,8 @@ const createPiSessionTools = (input, providerOptions, options = {}) => {
255
255
  const shouldReinitiateAll = hookContext.request.reinitiateAll;
256
256
  connectionContext.requestedToolkits = requestedToolkits;
257
257
  connectionContext.reinitiateAll = shouldReinitiateAll;
258
- const states = normalizeToolkitStateMap(await capabilities.connections?.getToolkitStates?.(requestedToolkits, connectionContext), requestedToolkits);
258
+ const statesRaw = await capabilities.connections?.getToolkitStates?.(requestedToolkits, connectionContext);
259
+ const states = normalizeToolkitStateMap(statesRaw, requestedToolkits);
259
260
  const results = {};
260
261
  for (const toolkit of requestedToolkits) {
261
262
  const state = states.get(toolkit.toLowerCase());
@@ -397,12 +398,13 @@ const createPiSessionTools = (input, providerOptions, options = {}) => {
397
398
  authLinks.push(...handledResult.authLinks);
398
399
  return handledResult.value;
399
400
  });
400
- return toPiResult(await maybeTransform(capabilities, {
401
+ const transformed = await maybeTransform(capabilities, {
401
402
  tool: "search",
402
403
  requestedToolkits: hookContext.context.requestedToolkits,
403
404
  value,
404
405
  context: hookContext.context
405
- }), formatter, {
406
+ });
407
+ return toPiResult(transformed, formatter, {
406
408
  slug: names.search,
407
409
  authLinks
408
410
  });
@@ -427,12 +429,13 @@ const createPiSessionTools = (input, providerOptions, options = {}) => {
427
429
  const toolkits = normalizeToolkits(params.toolkits) ?? [];
428
430
  try {
429
431
  const managed = await manageConnectionsForToolkits(toolCallId, params, toolkits, params.reinitiate_all ?? false);
430
- return toPiResult(await maybeTransform(capabilities, {
432
+ const transformed = await maybeTransform(capabilities, {
431
433
  tool: "manageConnections",
432
434
  requestedToolkits: toolkits,
433
435
  value: managed.value,
434
436
  context: managed.context
435
- }), formatter, {
437
+ });
438
+ return toPiResult(transformed, formatter, {
436
439
  slug: names.manageConnections,
437
440
  authLinks: managed.authLinks,
438
441
  denied: managed.denied
@@ -461,12 +464,13 @@ const createPiSessionTools = (input, providerOptions, options = {}) => {
461
464
  const args = params.arguments ?? {};
462
465
  try {
463
466
  const executed = await executeWithPolicy(toolCallId, names.execute, params, toolSlug, args, params.account);
464
- return toPiResult(await maybeTransform(capabilities, {
467
+ const transformed = await maybeTransform(capabilities, {
465
468
  tool: "execute",
466
469
  requestedToolkits: toolkitFromToolSlug(executed.context.toolSlug) ? [toolkitFromToolSlug(executed.context.toolSlug)] : void 0,
467
470
  value: executed.value,
468
471
  context: executed.context
469
- }), formatter, {
472
+ });
473
+ return toPiResult(transformed, formatter, {
470
474
  slug: executed.context.toolSlug || names.execute,
471
475
  authLinks: executed.authLinks,
472
476
  denied: executed.denied
@@ -529,11 +533,12 @@ const createPiSessionTools = (input, providerOptions, options = {}) => {
529
533
  hookContext.context = executed.context;
530
534
  return executed.value;
531
535
  });
532
- return toPiResult(await maybeTransform(capabilities, {
536
+ const transformed = await maybeTransform(capabilities, {
533
537
  tool: "remoteWorkbench",
534
538
  value,
535
539
  context: hookContext.context
536
- }), formatter, {
540
+ });
541
+ return toPiResult(transformed, formatter, {
537
542
  slug: hookContext.context.toolSlug,
538
543
  authLinks,
539
544
  denied: details.denied
@@ -579,11 +584,12 @@ const createPiSessionTools = (input, providerOptions, options = {}) => {
579
584
  hookContext.context = executed.context;
580
585
  return executed.value;
581
586
  });
582
- return toPiResult(await maybeTransform(capabilities, {
587
+ const transformed = await maybeTransform(capabilities, {
583
588
  tool: "remoteBash",
584
589
  value,
585
590
  context: hookContext.context
586
- }), formatter, {
591
+ });
592
+ return toPiResult(transformed, formatter, {
587
593
  slug: hookContext.context.toolSlug,
588
594
  authLinks,
589
595
  denied: details.denied
@@ -6,7 +6,7 @@ interface LocalWorkbenchSession {
6
6
  }
7
7
  //#endregion
8
8
  //#region src/workbench/local-workbench.d.ts
9
- declare function experimental_createLocalWorkbenchSession(composio: Composio, session: Session<unknown, unknown, never>): Promise<LocalWorkbenchSession>;
9
+ export declare function experimental_createLocalWorkbenchSession(composio: Composio, session: Session<unknown, unknown, never>): Promise<LocalWorkbenchSession>;
10
10
  //#endregion
11
11
  //#region src/workbench/shim.d.ts
12
12
  interface WorkbenchEnvOptions {
@@ -17,7 +17,7 @@ interface WorkbenchEnvOptions {
17
17
  interface PythonWorkbenchHelperSourceOptions {
18
18
  invokeLlmModel?: string;
19
19
  }
20
- declare function experimental_createWorkbenchEnv(env: WorkbenchEnvOptions): Record<string, string>;
21
- declare function experimental_createPythonWorkbenchHelperSource(opts?: PythonWorkbenchHelperSourceOptions): string;
20
+ export declare function experimental_createWorkbenchEnv(env: WorkbenchEnvOptions): Record<string, string>;
21
+ export declare function experimental_createPythonWorkbenchHelperSource(opts?: PythonWorkbenchHelperSourceOptions): string;
22
22
  //#endregion
23
- export { type LocalWorkbenchSession, type PythonWorkbenchHelperSourceOptions, type WorkbenchEnvOptions, experimental_createLocalWorkbenchSession, experimental_createPythonWorkbenchHelperSource, experimental_createWorkbenchEnv };
23
+ export type { LocalWorkbenchSession, PythonWorkbenchHelperSourceOptions, WorkbenchEnvOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@composio/experimental",
3
- "version": "0.2.3-beta.0",
3
+ "version": "0.2.3-beta.1",
4
4
  "description": "Experimental Composio integrations and helpers",
5
5
  "main": "dist/index.mjs",
6
6
  "type": "module",
@@ -54,7 +54,7 @@
54
54
  "license": "ISC",
55
55
  "dependencies": {
56
56
  "safe-stable-stringify": "^2.5.0",
57
- "typebox": "1.3.16"
57
+ "typebox": "1.3.27"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "@composio/core": ">=1.0.0-beta.0 <2.0.0",
@@ -70,13 +70,13 @@
70
70
  }
71
71
  },
72
72
  "devDependencies": {
73
- "@earendil-works/pi-coding-agent": "^0.84.1",
74
- "eve": "^0.31.3",
75
- "tsdown": "^0.22.14",
76
- "tsx": "^4.23.12",
73
+ "@earendil-works/pi-coding-agent": "^0.84.4",
74
+ "eve": "^0.52.1",
75
+ "tsdown": "^0.23.0",
76
+ "tsx": "^4.23.13",
77
77
  "typescript": "^7.0.2",
78
78
  "vitest": "^4.1.11",
79
- "@composio/core": "1.0.0-beta.0"
79
+ "@composio/core": "1.0.0-beta.1"
80
80
  },
81
81
  "scripts": {
82
82
  "clean": "git clean -xdf node_modules",