runwork 0.23.2 → 0.24.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.
@@ -81,6 +81,16 @@ export interface AgentDefinition {
81
81
  integrations?: string[];
82
82
  /** Entity names the agent can read/write */
83
83
  entities?: string[];
84
+ /**
85
+ * Endpoints on OTHER apps in this workspace that the agent may call, as
86
+ * `'<app>:<METHOD>:<path>'` — e.g. `'labcrm:GET:/v1/portal/catalog'`.
87
+ * `<app>` is the target app's slug; `<path>` is the path exactly as registered,
88
+ * `:param` placeholders included.
89
+ *
90
+ * Declared explicitly, like `entities` and `integrations`: an agent can only
91
+ * call what the app author listed, never an arbitrary endpoint.
92
+ */
93
+ appEndpoints?: string[];
84
94
  /** Memory strategy */
85
95
  memoryStrategy?: MemoryStrategy;
86
96
  /** Custom tools for this agent */
@@ -90,6 +100,27 @@ export interface AgentDefinition {
90
100
  /** Cost/time limits for task agent sandbox execution. Optional overrides. */
91
101
  executionLimits?: ExecutionLimits;
92
102
  }
103
+ /** A parsed `'<app>:<METHOD>:<path>'` agent endpoint reference. */
104
+ export interface AppEndpointRef {
105
+ app: string;
106
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
107
+ path: string;
108
+ }
109
+ /**
110
+ * Parse `'labcrm:GET:/v1/portal/invite/:token'`.
111
+ *
112
+ * Split on the first two colons only: the path itself contains colons for its
113
+ * `:param` segments, so a naive split would mangle every parameterized endpoint.
114
+ * Returns null for anything malformed rather than throwing, so one bad entry in an
115
+ * agent definition costs that one tool instead of the whole agent.
116
+ */
117
+ export declare function parseAppEndpointRef(ref: string): AppEndpointRef | null;
118
+ /**
119
+ * Stable, model-friendly tool name for an endpoint reference, e.g.
120
+ * `call_labcrm_get_v1_portal_invite`. Param segments are dropped so the name
121
+ * stays readable; the full path is in the tool description.
122
+ */
123
+ export declare function appEndpointToolName(ref: AppEndpointRef): string;
93
124
  /**
94
125
  * Custom tool definition for agents
95
126
  */
@@ -64,6 +64,13 @@ export declare class BaseAgent extends AIChatAgent<Env> {
64
64
  * Build tools for accessing entities using AI SDK tool() helper
65
65
  * Uses entity classes directly with EntityContext
66
66
  */
67
+ /**
68
+ * One tool per endpoint the agent is allowed to call on another app.
69
+ *
70
+ * Routed through `callAppEndpoint`, so it works in preview and production
71
+ * alike: a production app cannot HTTP-fetch a sibling's public URL.
72
+ */
73
+ private buildAppEndpointTools;
67
74
  private buildEntityTools;
68
75
  /**
69
76
  * Build tools for running complex tasks via a sandboxed AI sub-agent
@@ -15,11 +15,16 @@ type ZodSchema = z.ZodType<any, any, any>;
15
15
  export type EndpointAuthType = 'apiKey' | 'public';
16
16
  /**
17
17
  * Caller principal type resolved by the platform and passed via the
18
- * `X-Public-Endpoint-Auth-Type` header. `user` and `workspace_key` are
18
+ * `X-Public-Endpoint-Auth-Type` header. `user`, `workspace_key` and `app` are
19
19
  * authenticated principals the platform has already authorized; `api_key`
20
20
  * additionally carries a validated key id; `none` is unauthenticated.
21
+ *
22
+ * `app` means a sibling app in the same workspace called this endpoint through
23
+ * the platform (see `callAppEndpoint`). The platform records which app made the
24
+ * call, but does not forward that id here: it is self-asserted by the caller and
25
+ * must not be used for authorization until app identity is verifiable.
21
26
  */
22
- export type EndpointPrincipalType = 'none' | 'api_key' | 'workspace_key' | 'user';
27
+ export type EndpointPrincipalType = 'none' | 'api_key' | 'workspace_key' | 'user' | 'app';
23
28
  /**
24
29
  * HTTP methods supported by endpoints
25
30
  */
@@ -62,7 +67,7 @@ export interface EndpointContext<TQuery = Record<string, unknown>, TBody = unkno
62
67
  export interface EndpointAuthInfo {
63
68
  /** Authentication requirement declared by the endpoint */
64
69
  type: EndpointAuthType;
65
- /** Resolved caller principal type (api_key, workspace_key, user, none) */
70
+ /** Resolved caller principal type (api_key, workspace_key, user, app, none) */
66
71
  principalType?: EndpointPrincipalType;
67
72
  /** API key ID (if authenticated with an API key) */
68
73
  apiKeyId?: string;
@@ -162,6 +162,34 @@ export interface RegisterAgentRequest extends Record<string, unknown> {
162
162
  * WorkspaceContext - Helper for cross-app data queries
163
163
  * Provides methods to query entities from other apps in the same workspace
164
164
  */
165
+ /**
166
+ * Options for calling a public endpoint on another app in the workspace.
167
+ */
168
+ export interface CallAppEndpointOptions {
169
+ /**
170
+ * Target app, normally its slug as shown in the dashboard (e.g. 'labcrm').
171
+ * An app id or worker name also resolves. If the slug is wrong, the error
172
+ * response lists the slugs available in this workspace.
173
+ */
174
+ app: string;
175
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
176
+ /** Endpoint path exactly as registered, path params included: '/v1/orders/:id'. */
177
+ path: string;
178
+ /** Values for the `:param` segments in `path`. */
179
+ pathParams?: Record<string, string>;
180
+ queryParams?: Record<string, string>;
181
+ /** JSON body. Ignored for GET and HEAD. */
182
+ body?: unknown;
183
+ }
184
+ /**
185
+ * Result of a cross-app endpoint call. `ok` and `status` are the target
186
+ * endpoint's own response status, not the transport's.
187
+ */
188
+ export interface CallAppEndpointResult<T = unknown> {
189
+ ok: boolean;
190
+ status: number;
191
+ data: T;
192
+ }
165
193
  export declare class WorkspaceContext {
166
194
  private env;
167
195
  private workspaceId;
@@ -198,6 +226,45 @@ export declare class WorkspaceContext {
198
226
  * Delete an entity in another app in the workspace
199
227
  */
200
228
  deleteEntity(entityName: string, id: string): Promise<void>;
229
+ /**
230
+ * Transport for cross-app endpoint calls.
231
+ *
232
+ * Deliberately NOT `workspaceFetch`, for two reasons:
233
+ *
234
+ * 1. `workspaceFetch` retries over HTTP whenever the Durable Object returns a
235
+ * non-2xx. That is right for entity CRUD, where a non-2xx means the DO
236
+ * itself failed. Here a non-2xx is the TARGET ENDPOINT'S OWN ANSWER, so
237
+ * retrying would re-send the request — duplicating POSTs — and in production
238
+ * the retry goes to the platform's own domain, which a Workers for Platforms
239
+ * worker cannot fetch: it hangs until timeout, the very failure this function
240
+ * exists to avoid. A status is a result, never a transport error.
241
+ *
242
+ * 2. Production therefore uses the DO binding ONLY, mirroring `workspaceApiFetch`
243
+ * in core-utils.ts, which is the proven path for every other platform call
244
+ * made from a deployed app. Preview and sandbox keep the HTTP path, where the
245
+ * app is reached over a tunnel rather than the dispatch namespace.
246
+ */
247
+ private endpointCallFetch;
248
+ /**
249
+ * Call a public endpoint on another app in this workspace.
250
+ *
251
+ * Production apps run in a Workers for Platforms dispatch namespace and cannot
252
+ * HTTP-fetch the platform's app domain, so a direct `fetch()` to a sibling app's
253
+ * public URL hangs until it times out. This routes through the workspace instead,
254
+ * which reaches the target app via the dispatcher.
255
+ *
256
+ * The call arrives at the target as an `app` principal, which satisfies endpoints
257
+ * declared `auth: 'apiKey'`. No API key is needed or sent.
258
+ *
259
+ * @example
260
+ * const invite = await callAppEndpoint(env, {
261
+ * app: 'labcrm',
262
+ * method: 'GET',
263
+ * path: '/v1/portal/invite/:token',
264
+ * pathParams: { token },
265
+ * });
266
+ */
267
+ callAppEndpoint<T = unknown>(options: CallAppEndpointOptions): Promise<CallAppEndpointResult<T>>;
201
268
  /**
202
269
  * Register an entity with the workspace so other apps can query it
203
270
  */
@@ -430,6 +497,22 @@ export declare function listWorkspaceEntity<T = unknown>(env: Env, entityName: s
430
497
  * @example
431
498
  * const contact = await getWorkspaceEntity<Contact>(env, 'Contact', 'contact-123');
432
499
  */
500
+ /**
501
+ * Call a public endpoint on ANOTHER app in this workspace.
502
+ *
503
+ * Use this instead of `fetch()` against a sibling app's public URL: production apps
504
+ * cannot HTTP-fetch the platform's app domain and such a fetch hangs until timeout.
505
+ *
506
+ * @example
507
+ * const result = await callAppEndpoint(env, {
508
+ * app: 'labcrm',
509
+ * method: 'POST',
510
+ * path: '/v1/portal/orders',
511
+ * body: { items },
512
+ * });
513
+ * if (!result.ok) throw new Error(`CRM rejected the order: ${result.status}`);
514
+ */
515
+ export declare function callAppEndpoint<T = unknown>(env: Env, options: CallAppEndpointOptions): Promise<CallAppEndpointResult<T>>;
433
516
  export declare function getWorkspaceEntity<T = unknown>(env: Env, entityName: string, id: string): Promise<T | null>;
434
517
  /**
435
518
  * Create an entity in ANOTHER app in the workspace (cross-app ONLY)
@@ -1,2 +1,2 @@
1
- export { WorkspaceContext, getWorkspaceContext, listWorkspaceEntity, getWorkspaceEntity, createWorkspaceEntity, updateWorkspaceEntity, deleteWorkspaceEntity, initializeWorkspace, } from './core-workspace';
2
- export type { WorkspaceUser, ListUsersOptions, ListUsersResponse, NotifyUserParams, NotifyUserResult, ListEntityRequest, ListEntityResponse, GetEntityRequest, CreateEntityRequest, UpdateEntityRequest, DeleteEntityRequest, RegisterEntityRequest, RegisterAppRequest, RegisterComponentRequest, RegisterScheduleRequest, RegisterWorkflowRequest, RegisterEndpointRequest, RegisterIntegrationRequest, RegisterAgentRequest as WorkspaceRegisterAgentRequest, } from './core-workspace';
1
+ export { WorkspaceContext, getWorkspaceContext, listWorkspaceEntity, getWorkspaceEntity, createWorkspaceEntity, updateWorkspaceEntity, deleteWorkspaceEntity, callAppEndpoint, initializeWorkspace, } from './core-workspace';
2
+ export type { WorkspaceUser, ListUsersOptions, ListUsersResponse, NotifyUserParams, NotifyUserResult, ListEntityRequest, ListEntityResponse, GetEntityRequest, CreateEntityRequest, UpdateEntityRequest, DeleteEntityRequest, RegisterEntityRequest, RegisterAppRequest, RegisterComponentRequest, RegisterScheduleRequest, RegisterWorkflowRequest, RegisterEndpointRequest, RegisterIntegrationRequest, CallAppEndpointOptions, CallAppEndpointResult, RegisterAgentRequest as WorkspaceRegisterAgentRequest, } from './core-workspace';