runwork 0.24.0 → 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 `
|
|
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';
|
package/dist/index.js
CHANGED
|
@@ -5100,8 +5100,8 @@ export declare function componentRoutes(app: Hono<{
|
|
|
5100
5100
|
Bindings: Env;
|
|
5101
5101
|
}>): void;
|
|
5102
5102
|
`,
|
|
5103
|
-
"workspace.d.ts": `export { WorkspaceContext, getWorkspaceContext, listWorkspaceEntity, getWorkspaceEntity, createWorkspaceEntity, updateWorkspaceEntity, deleteWorkspaceEntity, initializeWorkspace, } from './core-workspace';
|
|
5104
|
-
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';
|
|
5103
|
+
"workspace.d.ts": `export { WorkspaceContext, getWorkspaceContext, listWorkspaceEntity, getWorkspaceEntity, createWorkspaceEntity, updateWorkspaceEntity, deleteWorkspaceEntity, callAppEndpoint, initializeWorkspace, } from './core-workspace';
|
|
5104
|
+
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';
|
|
5105
5105
|
`,
|
|
5106
5106
|
"core-scheduler.d.ts": `/**
|
|
5107
5107
|
* Core Scheduled Jobs Framework
|
|
@@ -5443,11 +5443,16 @@ type ZodSchema = z.ZodType<any, any, any>;
|
|
|
5443
5443
|
export type EndpointAuthType = 'apiKey' | 'public';
|
|
5444
5444
|
/**
|
|
5445
5445
|
* Caller principal type resolved by the platform and passed via the
|
|
5446
|
-
* \`X-Public-Endpoint-Auth-Type\` header. \`user\` and \`
|
|
5446
|
+
* \`X-Public-Endpoint-Auth-Type\` header. \`user\`, \`workspace_key\` and \`app\` are
|
|
5447
5447
|
* authenticated principals the platform has already authorized; \`api_key\`
|
|
5448
5448
|
* additionally carries a validated key id; \`none\` is unauthenticated.
|
|
5449
|
+
*
|
|
5450
|
+
* \`app\` means a sibling app in the same workspace called this endpoint through
|
|
5451
|
+
* the platform (see \`callAppEndpoint\`). The platform records which app made the
|
|
5452
|
+
* call, but does not forward that id here: it is self-asserted by the caller and
|
|
5453
|
+
* must not be used for authorization until app identity is verifiable.
|
|
5449
5454
|
*/
|
|
5450
|
-
export type EndpointPrincipalType = 'none' | 'api_key' | 'workspace_key' | 'user';
|
|
5455
|
+
export type EndpointPrincipalType = 'none' | 'api_key' | 'workspace_key' | 'user' | 'app';
|
|
5451
5456
|
/**
|
|
5452
5457
|
* HTTP methods supported by endpoints
|
|
5453
5458
|
*/
|
|
@@ -5490,7 +5495,7 @@ export interface EndpointContext<TQuery = Record<string, unknown>, TBody = unkno
|
|
|
5490
5495
|
export interface EndpointAuthInfo {
|
|
5491
5496
|
/** Authentication requirement declared by the endpoint */
|
|
5492
5497
|
type: EndpointAuthType;
|
|
5493
|
-
/** Resolved caller principal type (api_key, workspace_key, user, none) */
|
|
5498
|
+
/** Resolved caller principal type (api_key, workspace_key, user, app, none) */
|
|
5494
5499
|
principalType?: EndpointPrincipalType;
|
|
5495
5500
|
/** API key ID (if authenticated with an API key) */
|
|
5496
5501
|
apiKeyId?: string;
|
|
@@ -6319,6 +6324,34 @@ export interface RegisterAgentRequest extends Record<string, unknown> {
|
|
|
6319
6324
|
* WorkspaceContext - Helper for cross-app data queries
|
|
6320
6325
|
* Provides methods to query entities from other apps in the same workspace
|
|
6321
6326
|
*/
|
|
6327
|
+
/**
|
|
6328
|
+
* Options for calling a public endpoint on another app in the workspace.
|
|
6329
|
+
*/
|
|
6330
|
+
export interface CallAppEndpointOptions {
|
|
6331
|
+
/**
|
|
6332
|
+
* Target app, normally its slug as shown in the dashboard (e.g. 'labcrm').
|
|
6333
|
+
* An app id or worker name also resolves. If the slug is wrong, the error
|
|
6334
|
+
* response lists the slugs available in this workspace.
|
|
6335
|
+
*/
|
|
6336
|
+
app: string;
|
|
6337
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
6338
|
+
/** Endpoint path exactly as registered, path params included: '/v1/orders/:id'. */
|
|
6339
|
+
path: string;
|
|
6340
|
+
/** Values for the \`:param\` segments in \`path\`. */
|
|
6341
|
+
pathParams?: Record<string, string>;
|
|
6342
|
+
queryParams?: Record<string, string>;
|
|
6343
|
+
/** JSON body. Ignored for GET and HEAD. */
|
|
6344
|
+
body?: unknown;
|
|
6345
|
+
}
|
|
6346
|
+
/**
|
|
6347
|
+
* Result of a cross-app endpoint call. \`ok\` and \`status\` are the target
|
|
6348
|
+
* endpoint's own response status, not the transport's.
|
|
6349
|
+
*/
|
|
6350
|
+
export interface CallAppEndpointResult<T = unknown> {
|
|
6351
|
+
ok: boolean;
|
|
6352
|
+
status: number;
|
|
6353
|
+
data: T;
|
|
6354
|
+
}
|
|
6322
6355
|
export declare class WorkspaceContext {
|
|
6323
6356
|
private env;
|
|
6324
6357
|
private workspaceId;
|
|
@@ -6355,6 +6388,45 @@ export declare class WorkspaceContext {
|
|
|
6355
6388
|
* Delete an entity in another app in the workspace
|
|
6356
6389
|
*/
|
|
6357
6390
|
deleteEntity(entityName: string, id: string): Promise<void>;
|
|
6391
|
+
/**
|
|
6392
|
+
* Transport for cross-app endpoint calls.
|
|
6393
|
+
*
|
|
6394
|
+
* Deliberately NOT \`workspaceFetch\`, for two reasons:
|
|
6395
|
+
*
|
|
6396
|
+
* 1. \`workspaceFetch\` retries over HTTP whenever the Durable Object returns a
|
|
6397
|
+
* non-2xx. That is right for entity CRUD, where a non-2xx means the DO
|
|
6398
|
+
* itself failed. Here a non-2xx is the TARGET ENDPOINT'S OWN ANSWER, so
|
|
6399
|
+
* retrying would re-send the request — duplicating POSTs — and in production
|
|
6400
|
+
* the retry goes to the platform's own domain, which a Workers for Platforms
|
|
6401
|
+
* worker cannot fetch: it hangs until timeout, the very failure this function
|
|
6402
|
+
* exists to avoid. A status is a result, never a transport error.
|
|
6403
|
+
*
|
|
6404
|
+
* 2. Production therefore uses the DO binding ONLY, mirroring \`workspaceApiFetch\`
|
|
6405
|
+
* in core-utils.ts, which is the proven path for every other platform call
|
|
6406
|
+
* made from a deployed app. Preview and sandbox keep the HTTP path, where the
|
|
6407
|
+
* app is reached over a tunnel rather than the dispatch namespace.
|
|
6408
|
+
*/
|
|
6409
|
+
private endpointCallFetch;
|
|
6410
|
+
/**
|
|
6411
|
+
* Call a public endpoint on another app in this workspace.
|
|
6412
|
+
*
|
|
6413
|
+
* Production apps run in a Workers for Platforms dispatch namespace and cannot
|
|
6414
|
+
* HTTP-fetch the platform's app domain, so a direct \`fetch()\` to a sibling app's
|
|
6415
|
+
* public URL hangs until it times out. This routes through the workspace instead,
|
|
6416
|
+
* which reaches the target app via the dispatcher.
|
|
6417
|
+
*
|
|
6418
|
+
* The call arrives at the target as an \`app\` principal, which satisfies endpoints
|
|
6419
|
+
* declared \`auth: 'apiKey'\`. No API key is needed or sent.
|
|
6420
|
+
*
|
|
6421
|
+
* @example
|
|
6422
|
+
* const invite = await callAppEndpoint(env, {
|
|
6423
|
+
* app: 'labcrm',
|
|
6424
|
+
* method: 'GET',
|
|
6425
|
+
* path: '/v1/portal/invite/:token',
|
|
6426
|
+
* pathParams: { token },
|
|
6427
|
+
* });
|
|
6428
|
+
*/
|
|
6429
|
+
callAppEndpoint<T = unknown>(options: CallAppEndpointOptions): Promise<CallAppEndpointResult<T>>;
|
|
6358
6430
|
/**
|
|
6359
6431
|
* Register an entity with the workspace so other apps can query it
|
|
6360
6432
|
*/
|
|
@@ -6587,6 +6659,22 @@ export declare function listWorkspaceEntity<T = unknown>(env: Env, entityName: s
|
|
|
6587
6659
|
* @example
|
|
6588
6660
|
* const contact = await getWorkspaceEntity<Contact>(env, 'Contact', 'contact-123');
|
|
6589
6661
|
*/
|
|
6662
|
+
/**
|
|
6663
|
+
* Call a public endpoint on ANOTHER app in this workspace.
|
|
6664
|
+
*
|
|
6665
|
+
* Use this instead of \`fetch()\` against a sibling app's public URL: production apps
|
|
6666
|
+
* cannot HTTP-fetch the platform's app domain and such a fetch hangs until timeout.
|
|
6667
|
+
*
|
|
6668
|
+
* @example
|
|
6669
|
+
* const result = await callAppEndpoint(env, {
|
|
6670
|
+
* app: 'labcrm',
|
|
6671
|
+
* method: 'POST',
|
|
6672
|
+
* path: '/v1/portal/orders',
|
|
6673
|
+
* body: { items },
|
|
6674
|
+
* });
|
|
6675
|
+
* if (!result.ok) throw new Error(\`CRM rejected the order: \${result.status}\`);
|
|
6676
|
+
*/
|
|
6677
|
+
export declare function callAppEndpoint<T = unknown>(env: Env, options: CallAppEndpointOptions): Promise<CallAppEndpointResult<T>>;
|
|
6590
6678
|
export declare function getWorkspaceEntity<T = unknown>(env: Env, entityName: string, id: string): Promise<T | null>;
|
|
6591
6679
|
/**
|
|
6592
6680
|
* Create an entity in ANOTHER app in the workspace (cross-app ONLY)
|
|
@@ -6914,6 +7002,13 @@ export declare class BaseAgent extends AIChatAgent<Env> {
|
|
|
6914
7002
|
* Build tools for accessing entities using AI SDK tool() helper
|
|
6915
7003
|
* Uses entity classes directly with EntityContext
|
|
6916
7004
|
*/
|
|
7005
|
+
/**
|
|
7006
|
+
* One tool per endpoint the agent is allowed to call on another app.
|
|
7007
|
+
*
|
|
7008
|
+
* Routed through \`callAppEndpoint\`, so it works in preview and production
|
|
7009
|
+
* alike: a production app cannot HTTP-fetch a sibling's public URL.
|
|
7010
|
+
*/
|
|
7011
|
+
private buildAppEndpointTools;
|
|
6917
7012
|
private buildEntityTools;
|
|
6918
7013
|
/**
|
|
6919
7014
|
* Build tools for running complex tasks via a sandboxed AI sub-agent
|
|
@@ -7353,6 +7448,16 @@ export interface AgentDefinition {
|
|
|
7353
7448
|
integrations?: string[];
|
|
7354
7449
|
/** Entity names the agent can read/write */
|
|
7355
7450
|
entities?: string[];
|
|
7451
|
+
/**
|
|
7452
|
+
* Endpoints on OTHER apps in this workspace that the agent may call, as
|
|
7453
|
+
* \`'<app>:<METHOD>:<path>'\` — e.g. \`'labcrm:GET:/v1/portal/catalog'\`.
|
|
7454
|
+
* \`<app>\` is the target app's slug; \`<path>\` is the path exactly as registered,
|
|
7455
|
+
* \`:param\` placeholders included.
|
|
7456
|
+
*
|
|
7457
|
+
* Declared explicitly, like \`entities\` and \`integrations\`: an agent can only
|
|
7458
|
+
* call what the app author listed, never an arbitrary endpoint.
|
|
7459
|
+
*/
|
|
7460
|
+
appEndpoints?: string[];
|
|
7356
7461
|
/** Memory strategy */
|
|
7357
7462
|
memoryStrategy?: MemoryStrategy;
|
|
7358
7463
|
/** Custom tools for this agent */
|
|
@@ -7362,6 +7467,27 @@ export interface AgentDefinition {
|
|
|
7362
7467
|
/** Cost/time limits for task agent sandbox execution. Optional overrides. */
|
|
7363
7468
|
executionLimits?: ExecutionLimits;
|
|
7364
7469
|
}
|
|
7470
|
+
/** A parsed \`'<app>:<METHOD>:<path>'\` agent endpoint reference. */
|
|
7471
|
+
export interface AppEndpointRef {
|
|
7472
|
+
app: string;
|
|
7473
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
7474
|
+
path: string;
|
|
7475
|
+
}
|
|
7476
|
+
/**
|
|
7477
|
+
* Parse \`'labcrm:GET:/v1/portal/invite/:token'\`.
|
|
7478
|
+
*
|
|
7479
|
+
* Split on the first two colons only: the path itself contains colons for its
|
|
7480
|
+
* \`:param\` segments, so a naive split would mangle every parameterized endpoint.
|
|
7481
|
+
* Returns null for anything malformed rather than throwing, so one bad entry in an
|
|
7482
|
+
* agent definition costs that one tool instead of the whole agent.
|
|
7483
|
+
*/
|
|
7484
|
+
export declare function parseAppEndpointRef(ref: string): AppEndpointRef | null;
|
|
7485
|
+
/**
|
|
7486
|
+
* Stable, model-friendly tool name for an endpoint reference, e.g.
|
|
7487
|
+
* \`call_labcrm_get_v1_portal_invite\`. Param segments are dropped so the name
|
|
7488
|
+
* stays readable; the full path is in the tool description.
|
|
7489
|
+
*/
|
|
7490
|
+
export declare function appEndpointToolName(ref: AppEndpointRef): string;
|
|
7365
7491
|
/**
|
|
7366
7492
|
* Custom tool definition for agents
|
|
7367
7493
|
*/
|
|
@@ -7713,7 +7839,7 @@ function createKeyboardListener() {
|
|
|
7713
7839
|
}
|
|
7714
7840
|
|
|
7715
7841
|
// src/generated/version.ts
|
|
7716
|
-
var VERSION = "0.24.
|
|
7842
|
+
var VERSION = "0.24.1";
|
|
7717
7843
|
|
|
7718
7844
|
// src/commands/dev.ts
|
|
7719
7845
|
var exports_dev = {};
|
|
@@ -8762,10 +8888,19 @@ function saveDefaultWorkspace(workspaceId, workspaceName) {
|
|
|
8762
8888
|
function hasProjectConfig() {
|
|
8763
8889
|
return existsSync21(".runwork.json");
|
|
8764
8890
|
}
|
|
8891
|
+
function matchAppRef(apps, ref) {
|
|
8892
|
+
return apps.find((a) => a.id === ref || a.name === ref || a.slug === ref);
|
|
8893
|
+
}
|
|
8894
|
+
function filterRowsByApp(rows, appRef, apps) {
|
|
8895
|
+
const match = matchAppRef(apps, appRef);
|
|
8896
|
+
if (!match)
|
|
8897
|
+
return null;
|
|
8898
|
+
return rows.filter((row) => row.appId === match.id);
|
|
8899
|
+
}
|
|
8765
8900
|
async function resolveApp2(client, workspaceId, options = {}) {
|
|
8766
8901
|
if (options.app) {
|
|
8767
8902
|
const apps = await client.listApps(workspaceId);
|
|
8768
|
-
const match = apps
|
|
8903
|
+
const match = matchAppRef(apps, options.app);
|
|
8769
8904
|
if (!match) {
|
|
8770
8905
|
console.error(`App "${options.app}" not found in workspace.`);
|
|
8771
8906
|
process.exit(1);
|
|
@@ -19327,17 +19462,22 @@ function toRunworkInventory(ctx) {
|
|
|
19327
19462
|
mcpServerCount: ctx.mcpServerCount
|
|
19328
19463
|
};
|
|
19329
19464
|
}
|
|
19330
|
-
function buildAppSkillDescription(
|
|
19465
|
+
function buildAppSkillDescription(skill, registries) {
|
|
19466
|
+
const appName = skill.name;
|
|
19467
|
+
const fallback = `${appName} - Runwork workspace application`;
|
|
19331
19468
|
if (!registries)
|
|
19332
|
-
return
|
|
19469
|
+
return fallback;
|
|
19470
|
+
if (!skill.appId)
|
|
19471
|
+
return fallback;
|
|
19472
|
+
const appId = skill.appId;
|
|
19333
19473
|
const parts = [];
|
|
19334
|
-
const appEntities = registries.entities.filter((e) => e.
|
|
19335
|
-
const appSchedules = registries.schedules.filter((s) => s.
|
|
19336
|
-
const appWorkflows = registries.workflows.filter((w) => w.
|
|
19337
|
-
const appAgents = registries.agents.filter((a) => a.
|
|
19338
|
-
const appEndpoints = registries.endpoints.filter((e) => e.
|
|
19339
|
-
const appFileStorages = registries.fileStorages.filter((f) => f.
|
|
19340
|
-
const appComponents = registries.components.filter((c) => c.
|
|
19474
|
+
const appEntities = registries.entities.filter((e) => e.appId === appId);
|
|
19475
|
+
const appSchedules = registries.schedules.filter((s) => s.appId === appId);
|
|
19476
|
+
const appWorkflows = registries.workflows.filter((w) => w.appId === appId);
|
|
19477
|
+
const appAgents = registries.agents.filter((a) => a.appId === appId);
|
|
19478
|
+
const appEndpoints = registries.endpoints.filter((e) => e.appId === appId);
|
|
19479
|
+
const appFileStorages = registries.fileStorages.filter((f) => f.appId === appId);
|
|
19480
|
+
const appComponents = registries.components.filter((c) => c.appId === appId);
|
|
19341
19481
|
if (appEntities.length > 0)
|
|
19342
19482
|
parts.push(`entities (${appEntities.map((e) => e.entityName).join(", ")})`);
|
|
19343
19483
|
if (appFileStorages.length > 0)
|
|
@@ -19353,7 +19493,7 @@ function buildAppSkillDescription(appName, registries) {
|
|
|
19353
19493
|
if (appComponents.length > 0)
|
|
19354
19494
|
parts.push(`components (${appComponents.map((c) => c.componentName).join(", ")})`);
|
|
19355
19495
|
if (parts.length === 0)
|
|
19356
|
-
return
|
|
19496
|
+
return fallback;
|
|
19357
19497
|
return `${appName} - Runwork workspace app with ${parts.join(", ")}. Use this skill when you need data or capabilities from this app.`;
|
|
19358
19498
|
}
|
|
19359
19499
|
function generateIntroSkill(ctx) {
|
|
@@ -19877,7 +20017,12 @@ var listCommand3 = new Command17("list").description("List entities registered i
|
|
|
19877
20017
|
try {
|
|
19878
20018
|
let entities = await client.listEntities(workspaceId);
|
|
19879
20019
|
if (opts.app) {
|
|
19880
|
-
|
|
20020
|
+
const filtered = filterRowsByApp(entities, opts.app, await client.listApps(workspaceId));
|
|
20021
|
+
if (filtered === null) {
|
|
20022
|
+
console.error(`App "${opts.app}" not found in this workspace.`);
|
|
20023
|
+
process.exit(1);
|
|
20024
|
+
}
|
|
20025
|
+
entities = filtered;
|
|
19881
20026
|
}
|
|
19882
20027
|
if (opts.preview) {
|
|
19883
20028
|
entities = entities.filter((e) => e.deploymentMode === "preview");
|
|
@@ -20226,7 +20371,12 @@ var listCommand4 = new Command18("list").description("List workflows in a worksp
|
|
|
20226
20371
|
try {
|
|
20227
20372
|
let workflows = await client.listWorkflows(workspaceId);
|
|
20228
20373
|
if (opts.app) {
|
|
20229
|
-
|
|
20374
|
+
const filtered = filterRowsByApp(workflows, opts.app, await client.listApps(workspaceId));
|
|
20375
|
+
if (filtered === null) {
|
|
20376
|
+
console.error(`App "${opts.app}" not found in this workspace.`);
|
|
20377
|
+
process.exit(1);
|
|
20378
|
+
}
|
|
20379
|
+
workflows = filtered;
|
|
20230
20380
|
}
|
|
20231
20381
|
if (useJson) {
|
|
20232
20382
|
jsonOut({ workflows });
|
|
@@ -20585,7 +20735,10 @@ function truncate3(text2, max) {
|
|
|
20585
20735
|
return first;
|
|
20586
20736
|
return first.slice(0, max - 3) + "...";
|
|
20587
20737
|
}
|
|
20588
|
-
|
|
20738
|
+
function filterEndpointsByApp(endpoints, appRef, apps) {
|
|
20739
|
+
return filterRowsByApp(endpoints, appRef, apps);
|
|
20740
|
+
}
|
|
20741
|
+
var listCommand6 = new Command20("list").description("List workspace public endpoints").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <slug>", "Filter by app slug, name, or ID").action(async (opts, command) => {
|
|
20589
20742
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
20590
20743
|
const credentials = requireAuth();
|
|
20591
20744
|
const client = new ApiClient(credentials);
|
|
@@ -20593,7 +20746,12 @@ var listCommand6 = new Command20("list").description("List workspace public endp
|
|
|
20593
20746
|
try {
|
|
20594
20747
|
let endpoints = await client.listEndpoints(workspaceId);
|
|
20595
20748
|
if (opts.app) {
|
|
20596
|
-
|
|
20749
|
+
const filtered = filterEndpointsByApp(endpoints, opts.app, await client.listApps(workspaceId));
|
|
20750
|
+
if (filtered === null) {
|
|
20751
|
+
console.error(`App "${opts.app}" not found in this workspace.`);
|
|
20752
|
+
process.exit(1);
|
|
20753
|
+
}
|
|
20754
|
+
endpoints = filtered;
|
|
20597
20755
|
}
|
|
20598
20756
|
if (useJson) {
|
|
20599
20757
|
jsonOut({ endpoints });
|
|
@@ -20623,7 +20781,11 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
20623
20781
|
process.exit(1);
|
|
20624
20782
|
}
|
|
20625
20783
|
});
|
|
20626
|
-
|
|
20784
|
+
function methodsForPath(endpoints, path4) {
|
|
20785
|
+
const methods = endpoints.filter((e) => e.endpointPath === path4).map((e) => e.method.toUpperCase());
|
|
20786
|
+
return [...new Set(methods)].sort();
|
|
20787
|
+
}
|
|
20788
|
+
var callCommand2 = new Command20("call").description("Call a workspace endpoint directly").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("<path>", "Endpoint path (e.g. /my-endpoint)").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <slug>", "App slug, name, or ID (narrows endpoint lookup)").option("--body <json>", "Request body as JSON string").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <string>", 'Query string to append to the URL (e.g. "foo=bar&baz=1")').option("--api-key <key>", "API key for Authorization: Bearer header").action(async (method, path4, opts, command) => {
|
|
20627
20789
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
20628
20790
|
const credentials = requireAuth();
|
|
20629
20791
|
const client = new ApiClient(credentials);
|
|
@@ -20631,13 +20793,23 @@ var callCommand2 = new Command20("call").description("Call a workspace endpoint
|
|
|
20631
20793
|
try {
|
|
20632
20794
|
let endpoints = await client.listEndpoints(workspaceId);
|
|
20633
20795
|
if (opts.app) {
|
|
20634
|
-
|
|
20796
|
+
const filtered = filterEndpointsByApp(endpoints, opts.app, await client.listApps(workspaceId));
|
|
20797
|
+
if (filtered === null) {
|
|
20798
|
+
console.error(`App "${opts.app}" not found in this workspace.`);
|
|
20799
|
+
process.exit(1);
|
|
20800
|
+
}
|
|
20801
|
+
endpoints = filtered;
|
|
20635
20802
|
}
|
|
20636
20803
|
const targetMethod = method.toUpperCase();
|
|
20637
20804
|
const endpoint = endpoints.find((e) => e.method.toUpperCase() === targetMethod && e.endpointPath === path4);
|
|
20638
20805
|
if (!endpoint) {
|
|
20639
20806
|
console.error(`Endpoint not found: ${targetMethod} ${path4}`);
|
|
20640
|
-
|
|
20807
|
+
const otherMethods = methodsForPath(endpoints, path4);
|
|
20808
|
+
if (otherMethods.length > 0) {
|
|
20809
|
+
console.error(`
|
|
20810
|
+
${path4} is registered, but not for ${targetMethod}. Try: ${otherMethods.join(", ")}`);
|
|
20811
|
+
console.error(` runwork endpoints call ${otherMethods[0]} ${path4}`);
|
|
20812
|
+
} else if (endpoints.length > 0) {
|
|
20641
20813
|
console.error(`
|
|
20642
20814
|
Available endpoints:`);
|
|
20643
20815
|
for (const e of endpoints) {
|
|
@@ -20907,7 +21079,12 @@ var listCommand8 = new Command22("list").description("List components registered
|
|
|
20907
21079
|
try {
|
|
20908
21080
|
let components = await client.listComponents(workspaceId);
|
|
20909
21081
|
if (opts.app) {
|
|
20910
|
-
|
|
21082
|
+
const filtered = filterRowsByApp(components, opts.app, await client.listApps(workspaceId));
|
|
21083
|
+
if (filtered === null) {
|
|
21084
|
+
console.error(`App "${opts.app}" not found in this workspace.`);
|
|
21085
|
+
process.exit(1);
|
|
21086
|
+
}
|
|
21087
|
+
components = filtered;
|
|
20911
21088
|
}
|
|
20912
21089
|
if (useJson) {
|
|
20913
21090
|
jsonOut({ components });
|
|
@@ -21040,7 +21217,12 @@ var listCommand10 = new Command24("list").description("List agents in workspace"
|
|
|
21040
21217
|
try {
|
|
21041
21218
|
let agents = await client.listAgents(workspaceId);
|
|
21042
21219
|
if (opts.app) {
|
|
21043
|
-
|
|
21220
|
+
const filtered = filterRowsByApp(agents, opts.app, await client.listApps(workspaceId));
|
|
21221
|
+
if (filtered === null) {
|
|
21222
|
+
console.error(`App "${opts.app}" not found in this workspace.`);
|
|
21223
|
+
process.exit(1);
|
|
21224
|
+
}
|
|
21225
|
+
agents = filtered;
|
|
21044
21226
|
}
|
|
21045
21227
|
if (useJson) {
|
|
21046
21228
|
jsonOut({ agents });
|
|
@@ -22574,7 +22756,7 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
|
|
|
22574
22756
|
name: s.name,
|
|
22575
22757
|
filename: s.name.toLowerCase().replace(/[^a-z0-9]+/g, "-"),
|
|
22576
22758
|
content: s.content,
|
|
22577
|
-
description: s.source === "app" ? buildAppSkillDescription(s
|
|
22759
|
+
description: s.source === "app" ? buildAppSkillDescription(s, registries) || `${s.name} - Runwork workspace application` : `${s.name} - Runwork workspace skill`
|
|
22578
22760
|
}));
|
|
22579
22761
|
const allSkillFiles = [...builtInSkills, ...workspaceSkillFiles];
|
|
22580
22762
|
const written = await adapter2.writeSkills(allSkillFiles, scope);
|
|
@@ -23337,7 +23519,7 @@ var buildPluginCommand = new Command29("build-plugin").description("Build an ins
|
|
|
23337
23519
|
name: s.name,
|
|
23338
23520
|
filename: s.name.toLowerCase().replace(/[^a-z0-9]+/g, "-"),
|
|
23339
23521
|
content: s.content,
|
|
23340
|
-
description: s.source === "app" ? buildAppSkillDescription(s
|
|
23522
|
+
description: s.source === "app" ? buildAppSkillDescription(s, registries) || `${s.name} - Runwork workspace application` : `${s.name} - Runwork workspace skill`
|
|
23341
23523
|
}))
|
|
23342
23524
|
];
|
|
23343
23525
|
const teamInstructions = onboardingConfig?.config?.teamInstructions;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "runwork",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.1",
|
|
4
4
|
"description": "CLI for Runwork: develop, preview, and deploy Runwork apps from your local machine.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "Runwork, Inc. <info@runwork.ai> (https://www.runwork.ai)",
|