esoul-sdk 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/api-reference.md +88 -11
- package/dist/agent-wait.d.ts +47 -0
- package/dist/agent-wait.js +47 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/manifest.d.ts +44 -44
- package/dist/react.d.ts +9 -0
- package/dist/react.js +9 -0
- package/dist/server.d.ts +74 -4
- package/dist/server.js +29 -2
- package/dist/types.d.ts +9 -0
- package/docs/03-events-and-state.md +14 -7
- package/docs/04-tools.md +27 -0
- package/docs/05-ui.md +20 -0
- package/docs/06-server.md +25 -0
- package/llms-full.txt +86 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
Releases before 0.20.0 are recorded in the repository history only.
|
|
4
4
|
|
|
5
|
+
## 0.24.0
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `questions(ctx)` (esoul-sdk/server): a question your app needs the person to answer reaches the
|
|
10
|
+
platform's questions bell on every workspace — options as buttons, an Open button that lands on
|
|
11
|
+
the place inside your app (`useAppNav`), and the answer delivered to your own op as the person who
|
|
12
|
+
answered. `settle(key, …)` closes it when your own screen took the answer (docs/06-server.md,
|
|
13
|
+
"Asking the person").
|
|
14
|
+
- `mailWaitDirective(runCtx, …)`: an app tool pauses an agent network run until mail arrives at this
|
|
15
|
+
inbox on a thread or from a sender — the platform's own wait kernel (docs/04-tools.md, "Waiting
|
|
16
|
+
inside a network run").
|
|
17
|
+
|
|
18
|
+
## 0.23.0
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `useAppNav(nodeId, onTarget)` (esoul-sdk/react): the platform opens a place INSIDE your app —
|
|
23
|
+
the tasks pane lands on a conversation or a campaign, not just the app (docs/05-ui.md, "Opened
|
|
24
|
+
from outside").
|
|
25
|
+
- `origin: "server"` on an event definition: only the app's own server code (ops, routes, tasks,
|
|
26
|
+
webhooks) may append it; the browser's append and offline-queue doors and the PAT / SDK / MCP
|
|
27
|
+
dispatch routes refuse it (docs/03-events-and-state.md, "Events only the server emits").
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- `readAppState(nodeId)` reads only for the call the platform is running: your app and its own
|
|
32
|
+
type in your workspace, another type only with a `workspaceTools` grant for it (refused with the
|
|
33
|
+
line to add), null for an app in another workspace, own type only from a webhook, and a throw
|
|
34
|
+
outside an op, route, task or webhook. `callWorkspaceTool` refuses a `pluginId`/`nodeId` that is
|
|
35
|
+
not the running call's own. The Forge box applies the same read rule.
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- `pluginServer.fileProducers` takes a producer with its own key type: `PluginFileProducer<MyKey>`
|
|
40
|
+
with `MyKey` declared as an `interface` no longer fails to typecheck against the map.
|
|
41
|
+
|
|
5
42
|
## 0.22.0
|
|
6
43
|
|
|
7
44
|
### Added
|
package/api-reference.md
CHANGED
|
@@ -7,11 +7,11 @@ the complete list it teaches from. In a Forge workbench the source itself is rea
|
|
|
7
7
|
Regenerate: `npm run docs:api`.
|
|
8
8
|
|
|
9
9
|
==============================================================================
|
|
10
|
-
## `esoul-sdk` —
|
|
10
|
+
## `esoul-sdk` — 252 exports
|
|
11
11
|
|
|
12
12
|
Manifest, events, tools, ops, bindings, contracts, charts, access words — what app.tsx and the shared modules import.
|
|
13
13
|
|
|
14
|
-
### Functions and values (
|
|
14
|
+
### Functions and values (151)
|
|
15
15
|
|
|
16
16
|
#### `ASSET_APP_MAX_BYTES` — const · src/assets.ts
|
|
17
17
|
|
|
@@ -621,6 +621,14 @@ A gateway model id: `provider/model` ("deepseek/deepseek-v3.2").
|
|
|
621
621
|
const LLM_MODEL_ID_RE: RegExp
|
|
622
622
|
```
|
|
623
623
|
|
|
624
|
+
#### `mailWaitDirective` — function · src/agent-wait.ts
|
|
625
|
+
|
|
626
|
+
The wait's event, for the toolkit's `eventCallback`. Throws on a malformed wait.
|
|
627
|
+
|
|
628
|
+
```ts
|
|
629
|
+
function mailWaitDirective(runCtx: AgentRunToolContext, a: MailWaitArgs): Record<string, unknown>
|
|
630
|
+
```
|
|
631
|
+
|
|
624
632
|
#### `makeOpTool` — function · src/ops.ts
|
|
625
633
|
|
|
626
634
|
`opTool`, bound to a caller. The package binds its own `callPluginOp`; the platform binds the one that carries the acting viewer and targets this deployment — same tool, different wire, decided once at the index.
|
|
@@ -1213,7 +1221,7 @@ A manifest with one entry removed (the bytes stay; they may be shared). Pure.
|
|
|
1213
1221
|
function withoutAsset(assets: AssetsManifest | null | undefined, pluginId: string, name: string): AssetsManifest
|
|
1214
1222
|
```
|
|
1215
1223
|
|
|
1216
|
-
### Types (
|
|
1224
|
+
### Types (101)
|
|
1217
1225
|
|
|
1218
1226
|
#### `AgentRunToolContext` — interface · src/types.ts
|
|
1219
1227
|
|
|
@@ -1723,6 +1731,7 @@ interface EventDefinition<StateType extends ApplicationIdentifier> {
|
|
|
1723
1731
|
triggerMeta?: TriggerMeta;
|
|
1724
1732
|
sideEffect?: EventSideEffect;
|
|
1725
1733
|
permission?: "user_exclusive";
|
|
1734
|
+
origin?: "server";
|
|
1726
1735
|
conflictPolicy?: "mark" | "silent";
|
|
1727
1736
|
conflictScope?: (eventData: any) => string[] | null | undefined;
|
|
1728
1737
|
merge?: MergeDescription;
|
|
@@ -1975,6 +1984,25 @@ interface LabelShape {
|
|
|
1975
1984
|
}
|
|
1976
1985
|
```
|
|
1977
1986
|
|
|
1987
|
+
#### `MailWaitArgs` — interface · src/agent-wait.ts
|
|
1988
|
+
|
|
1989
|
+
```ts
|
|
1990
|
+
interface MailWaitArgs {
|
|
1991
|
+
workspaceId: string;
|
|
1992
|
+
inboxNodeId: string;
|
|
1993
|
+
inboxName: string;
|
|
1994
|
+
toolName: string;
|
|
1995
|
+
threadId?: string;
|
|
1996
|
+
fromEmail?: string;
|
|
1997
|
+
subject?: string;
|
|
1998
|
+
afterTimestamp: number;
|
|
1999
|
+
timeoutSeconds?: number;
|
|
2000
|
+
directiveId: string;
|
|
2001
|
+
onResume?: string;
|
|
2002
|
+
onTimeout?: string;
|
|
2003
|
+
}
|
|
2004
|
+
```
|
|
2005
|
+
|
|
1978
2006
|
#### `MergeDescription` — interface · src/types.ts
|
|
1979
2007
|
|
|
1980
2008
|
```ts
|
|
@@ -2393,11 +2421,11 @@ interface UsesDecl {
|
|
|
2393
2421
|
```
|
|
2394
2422
|
|
|
2395
2423
|
==============================================================================
|
|
2396
|
-
## `esoul-sdk/server` —
|
|
2424
|
+
## `esoul-sdk/server` — 115 exports
|
|
2397
2425
|
|
|
2398
2426
|
Server code only (server.ts, ops, routes, tasks): the viewer, the app's database, files, connections, machines, charts, route tokens.
|
|
2399
2427
|
|
|
2400
|
-
### Functions and values (
|
|
2428
|
+
### Functions and values (36)
|
|
2401
2429
|
|
|
2402
2430
|
#### `APPROVAL_WAIT` — const · src/computer.ts
|
|
2403
2431
|
|
|
@@ -2631,9 +2659,17 @@ The consent-enforcing files API for plugin server code. Every call re-checks you
|
|
|
2631
2659
|
function pluginFiles(_ctx: PluginFilesCtx): Promise<FilesApi>
|
|
2632
2660
|
```
|
|
2633
2661
|
|
|
2662
|
+
#### `questions` — function · src/server.ts
|
|
2663
|
+
|
|
2664
|
+
THE PLATFORM'S QUESTIONS BELL. A question an app needs the person to answer (an agent waiting on a decision) reaches them wherever they are — the bell, on every workspace — not only when they open the app:
|
|
2665
|
+
|
|
2666
|
+
```ts
|
|
2667
|
+
function questions(_ctx: { pluginId: string; workspaceId: string; nodeId: string; viewer?: { userId: string | null } }): Questions
|
|
2668
|
+
```
|
|
2669
|
+
|
|
2634
2670
|
#### `readAppState` — function · src/server.ts
|
|
2635
2671
|
|
|
2636
|
-
Read one app's state folded to head, by nodeId — server truth for an op or a
|
|
2672
|
+
Read one app's state folded to head, by nodeId — server truth for an op, route, task or webhook. It reads for the app instance of the call the platform is running: your own app and other instances of its type in your workspace; another app type only when plugin.json `workspaceTools` grants a tool of that type (the refusal names the line to add). Null when no such app exists — an app in another workspace is null too. A webhook (it runs for no instance) finds only instances of its own type. Outside a running call it throws. HOST-ONLY.
|
|
2637
2673
|
|
|
2638
2674
|
```ts
|
|
2639
2675
|
function readAppState( _nodeId: string, ): Promise<{ nodeId: string; workspaceId: string; applicationType: string; foldedSeq: number; state: Record<string, unknown> } | null>
|
|
@@ -2679,7 +2715,23 @@ WHO IS THIS, IN WORDS. The caller's own name and email, for an app with a reason
|
|
|
2679
2715
|
function viewerProfile(_viewer: PluginViewer): Promise<ViewerProfile | null>
|
|
2680
2716
|
```
|
|
2681
2717
|
|
|
2682
|
-
### Types (
|
|
2718
|
+
### Types (79)
|
|
2719
|
+
|
|
2720
|
+
#### `AppQuestion` — interface · src/server.ts
|
|
2721
|
+
|
|
2722
|
+
A question for the person (questions(ctx).ask).
|
|
2723
|
+
|
|
2724
|
+
```ts
|
|
2725
|
+
interface AppQuestion {
|
|
2726
|
+
key: string;
|
|
2727
|
+
question: string;
|
|
2728
|
+
options?: string[];
|
|
2729
|
+
details?: Record<string, unknown>;
|
|
2730
|
+
open?: { kind: string; key: string; label?: string };
|
|
2731
|
+
answer: { op: string; args?: Record<string, unknown> };
|
|
2732
|
+
expiresInSeconds?: number;
|
|
2733
|
+
}
|
|
2734
|
+
```
|
|
2683
2735
|
|
|
2684
2736
|
#### `AppRolePerson` — interface · src/server.ts
|
|
2685
2737
|
|
|
@@ -3387,7 +3439,7 @@ interface PluginServerModule {
|
|
|
3387
3439
|
webhooks?: Record<string, PluginWebhookHandler>;
|
|
3388
3440
|
ops?: Record<string, PluginOpHandler>;
|
|
3389
3441
|
routes?: Record<string, PluginRouteHandler>;
|
|
3390
|
-
fileProducers?: Record<string, PluginFileProducer
|
|
3442
|
+
fileProducers?: Record<string, PluginFileProducer<any>>;
|
|
3391
3443
|
}
|
|
3392
3444
|
```
|
|
3393
3445
|
|
|
@@ -3478,6 +3530,15 @@ interface ProgramStepState {
|
|
|
3478
3530
|
}
|
|
3479
3531
|
```
|
|
3480
3532
|
|
|
3533
|
+
#### `Questions` — interface · src/server.ts
|
|
3534
|
+
|
|
3535
|
+
```ts
|
|
3536
|
+
interface Questions {
|
|
3537
|
+
ask(q: AppQuestion): Promise<{ questionId: string; created: boolean }>;
|
|
3538
|
+
settle(key: string, outcome: { answer: string } | { cancelled: true }): Promise<void>;
|
|
3539
|
+
}
|
|
3540
|
+
```
|
|
3541
|
+
|
|
3481
3542
|
#### `RouteTokenGrant` — interface · src/server.ts
|
|
3482
3543
|
|
|
3483
3544
|
```ts
|
|
@@ -3689,11 +3750,11 @@ type WorkspaceGrant = { scope: "folder"; root: string } | { scope: "computer" };
|
|
|
3689
3750
|
```
|
|
3690
3751
|
|
|
3691
3752
|
==============================================================================
|
|
3692
|
-
## `esoul-sdk/react` —
|
|
3753
|
+
## `esoul-sdk/react` — 71 exports
|
|
3693
3754
|
|
|
3694
3755
|
The app's UI: hooks for the viewer, the app's state, realtime, workspace files and tools.
|
|
3695
3756
|
|
|
3696
|
-
### Functions and values (
|
|
3757
|
+
### Functions and values (37)
|
|
3697
3758
|
|
|
3698
3759
|
#### `ConnectAccount` — function · src/react.ts
|
|
3699
3760
|
|
|
@@ -3815,6 +3876,14 @@ True when the current viewer may mutate this workspace.
|
|
|
3815
3876
|
function useAppCanEdit(): boolean
|
|
3816
3877
|
```
|
|
3817
3878
|
|
|
3879
|
+
#### `useAppNav` — function · src/react.ts
|
|
3880
|
+
|
|
3881
|
+
"Open THIS inside the app": the platform's tasks pane, a link chip or a recall hit asks for a place inside this app instance (the keys are the app's own — say which in your tool and task descriptions). `onTarget` runs with the target waiting when the app mounts, and with each one asked for while it is on screen. Open it and select it; an unknown key does nothing.
|
|
3882
|
+
|
|
3883
|
+
```ts
|
|
3884
|
+
function useAppNav(_nodeId: string, _onTarget: (target: AppNavTarget) => void): void
|
|
3885
|
+
```
|
|
3886
|
+
|
|
3818
3887
|
#### `useCredential` — function · src/react.ts
|
|
3819
3888
|
|
|
3820
3889
|
The state of one of your plugin.json `credentials` slots for the person looking at the app.
|
|
@@ -3983,7 +4052,15 @@ The account's computers as a panel: online, the apps each serves, Disconnect.
|
|
|
3983
4052
|
function YourComputers(_props: { className?: string }): any
|
|
3984
4053
|
```
|
|
3985
4054
|
|
|
3986
|
-
### Types (
|
|
4055
|
+
### Types (34)
|
|
4056
|
+
|
|
4057
|
+
#### `AppNavTarget` — type · src/react.ts
|
|
4058
|
+
|
|
4059
|
+
A place inside an app, as named by whoever asks to open it: `{ thread: "…" }`, `{ campaign: "…" }`.
|
|
4060
|
+
|
|
4061
|
+
```ts
|
|
4062
|
+
type AppNavTarget = Record<string, string>;
|
|
4063
|
+
```
|
|
3987
4064
|
|
|
3988
4065
|
#### `DeviceRunStarted` — interface · src/device.ts
|
|
3989
4066
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A DURABLE MAIL WAIT from an app's tool inside an agent network run: the run
|
|
3
|
+
* pauses — minutes or days, nothing running — until mail arrives at this inbox
|
|
4
|
+
* on a thread or from a sender, then resumes with the arrival in its history.
|
|
5
|
+
*
|
|
6
|
+
* The platform's agent runtime owns the wait (the same kernel `wait_for_reply`
|
|
7
|
+
* uses): it parks on `workspace/email.message_arrived`, checks the inbox's
|
|
8
|
+
* folded `messages` for an arrival newer than `afterTimestamp` before and
|
|
9
|
+
* after parking, and resumes with `onResume` (its `{{messageId}}`, `{{from}}`,
|
|
10
|
+
* `{{subject}}`, `{{threadId}}` filled in) or `onTimeout`.
|
|
11
|
+
*
|
|
12
|
+
* toolkitCreator: (identifier, _chat, eventCallback, _msg, runCtx) => ({
|
|
13
|
+
* [`wait_for_email_${base}`]: { …, execute: async (args) => {
|
|
14
|
+
* if (!runCtx) return "Only inside an agent network run.";
|
|
15
|
+
* eventCallback(mailWaitDirective(runCtx, { workspaceId, inboxNodeId, inboxName, toolName, threadId, afterTimestamp, directiveId }));
|
|
16
|
+
* runCtx.setWaitDirectiveCreatedThisStep();
|
|
17
|
+
* return "Waiting…";
|
|
18
|
+
* } },
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* The inbox's state must keep a `messages` map (`{ id, threadId, labelIds,
|
|
22
|
+
* from, subject, internalDate }`) and its app must announce arrivals as that
|
|
23
|
+
* event (the platform does it for the SDK Gmail app). Pure.
|
|
24
|
+
*/
|
|
25
|
+
import type { AgentRunToolContext } from "./types.js";
|
|
26
|
+
export interface MailWaitArgs {
|
|
27
|
+
workspaceId: string;
|
|
28
|
+
/** The inbox app instance (the wait is scoped to it). */
|
|
29
|
+
inboxNodeId: string;
|
|
30
|
+
inboxName: string;
|
|
31
|
+
/** The tool's name as the model sees it (for the run's log). */
|
|
32
|
+
toolName: string;
|
|
33
|
+
/** Exactly one of: the next message on this thread, or from this sender (optionally with this subject). */
|
|
34
|
+
threadId?: string;
|
|
35
|
+
fromEmail?: string;
|
|
36
|
+
subject?: string;
|
|
37
|
+
/** Only mail newer than this counts (epoch ms) — the newest message the agent has already seen. */
|
|
38
|
+
afterTimestamp: number;
|
|
39
|
+
/** Default 7 days. */
|
|
40
|
+
timeoutSeconds?: number;
|
|
41
|
+
/** Unique per wait (the caller's id — keep it stable across a retried tool call). */
|
|
42
|
+
directiveId: string;
|
|
43
|
+
onResume?: string;
|
|
44
|
+
onTimeout?: string;
|
|
45
|
+
}
|
|
46
|
+
/** The wait's event, for the toolkit's `eventCallback`. Throws on a malformed wait. */
|
|
47
|
+
export declare function mailWaitDirective(runCtx: AgentRunToolContext, a: MailWaitArgs): Record<string, unknown>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const esc = (s) => s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
2
|
+
/** The wait's event, for the toolkit's `eventCallback`. Throws on a malformed wait. */
|
|
3
|
+
export function mailWaitDirective(runCtx, a) {
|
|
4
|
+
const threadId = a.threadId?.trim() || undefined;
|
|
5
|
+
const fromEmail = a.fromEmail?.trim() || undefined;
|
|
6
|
+
const subject = a.subject?.trim() || undefined;
|
|
7
|
+
if (!!threadId === !!fromEmail)
|
|
8
|
+
throw new Error("mailWaitDirective: give threadId OR fromEmail.");
|
|
9
|
+
const timeoutSeconds = Math.max(60, Math.min(30 * 86_400, Math.round(a.timeoutSeconds ?? 7 * 86_400)));
|
|
10
|
+
const scope = `async.data.workspaceId == "${esc(a.workspaceId)}" && async.data.nodeId == "${esc(a.inboxNodeId)}" && `;
|
|
11
|
+
const matchExpression = threadId
|
|
12
|
+
? `${scope}async.data.threadId == "${esc(threadId)}" && !async.data.labelIds.exists(l, l == "SENT")`
|
|
13
|
+
: `${scope}async.data.fromEmail == "${esc(fromEmail.toLowerCase())}" && ` +
|
|
14
|
+
(subject ? `async.data.subject == "${esc(subject)}" && ` : "") +
|
|
15
|
+
`!async.data.labelIds.exists(l, l == "SENT")`;
|
|
16
|
+
const what = threadId ? `thread ${threadId}` : `sender ${fromEmail}${subject ? ` subject "${subject}"` : ""}`;
|
|
17
|
+
return {
|
|
18
|
+
eventName: "agent_wait_directive_created",
|
|
19
|
+
eventData: {
|
|
20
|
+
runId: runCtx.agentRunId,
|
|
21
|
+
directiveId: a.directiveId,
|
|
22
|
+
agentNodeId: runCtx.currentAgentNodeId ?? null,
|
|
23
|
+
toolName: a.toolName,
|
|
24
|
+
eventName: "workspace/email.message_arrived",
|
|
25
|
+
matchExpression,
|
|
26
|
+
timeoutSeconds,
|
|
27
|
+
templates: {
|
|
28
|
+
onResume: a.onResume ?? `[Email landed in "${a.inboxName}" (${what}): messageId={{messageId}}, from={{from}}, subject="{{subject}}", threadId={{threadId}}.]`,
|
|
29
|
+
onTimeout: a.onTimeout ?? `[No email in "${a.inboxName}" (${what}) within ${timeoutSeconds}s.]`,
|
|
30
|
+
},
|
|
31
|
+
reason: `Waiting for email in ${a.inboxName} (${what})`,
|
|
32
|
+
prewaitCheck: {
|
|
33
|
+
type: "workspace_email_arrival",
|
|
34
|
+
workspaceId: a.workspaceId,
|
|
35
|
+
nodeId: a.inboxNodeId,
|
|
36
|
+
...(threadId ? { threadId } : { fromEmail }),
|
|
37
|
+
...(subject && !threadId ? { subject } : {}),
|
|
38
|
+
afterTimestamp: a.afterTimestamp,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
timestamp: Date.now(),
|
|
42
|
+
workspaceId: a.workspaceId,
|
|
43
|
+
applicationId: runCtx.agentBuilderNodeId,
|
|
44
|
+
instanceName: "",
|
|
45
|
+
chatIdSource: runCtx.agentRunId,
|
|
46
|
+
};
|
|
47
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export * from "./chart.js";
|
|
|
25
25
|
* the decision and the merges (records by id, fields, lines). The hook is `useRemoteReconcile` in esoul-sdk/react.
|
|
26
26
|
*/
|
|
27
27
|
export * from "./editor-sync.js";
|
|
28
|
+
export * from "./agent-wait.js";
|
|
28
29
|
/**
|
|
29
30
|
* The agent tool for one op, declared once: `opTool(ops.play, { say })` in app.tsx gives a tool whose
|
|
30
31
|
* parameters ARE the op's zod input and whose call goes to `callPluginOp` — as the acting viewer on
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ export * from "./chart.js";
|
|
|
25
25
|
* the decision and the merges (records by id, fields, lines). The hook is `useRemoteReconcile` in esoul-sdk/react.
|
|
26
26
|
*/
|
|
27
27
|
export * from "./editor-sync.js";
|
|
28
|
+
export * from "./agent-wait.js";
|
|
28
29
|
import { callPluginOp } from "./helpers.js";
|
|
29
30
|
import { makeOpTool } from "./ops.js";
|
|
30
31
|
/**
|
package/dist/manifest.d.ts
CHANGED
|
@@ -62,8 +62,8 @@ export declare const PluginConnectionSchema: z.ZodEffects<z.ZodObject<{
|
|
|
62
62
|
/** apiKey: header NAMES the plugin will send (never values). */
|
|
63
63
|
headerNames: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
64
64
|
}, "strict", z.ZodTypeAny, {
|
|
65
|
-
label: string;
|
|
66
65
|
kind: "oauth2" | "apiKey";
|
|
66
|
+
label: string;
|
|
67
67
|
key: string;
|
|
68
68
|
description?: string | undefined;
|
|
69
69
|
authorizeUrl?: string | undefined;
|
|
@@ -73,8 +73,8 @@ export declare const PluginConnectionSchema: z.ZodEffects<z.ZodObject<{
|
|
|
73
73
|
clientSecretEnv?: string | undefined;
|
|
74
74
|
headerNames?: string[] | undefined;
|
|
75
75
|
}, {
|
|
76
|
-
label: string;
|
|
77
76
|
kind: "oauth2" | "apiKey";
|
|
77
|
+
label: string;
|
|
78
78
|
key: string;
|
|
79
79
|
description?: string | undefined;
|
|
80
80
|
authorizeUrl?: string | undefined;
|
|
@@ -84,8 +84,8 @@ export declare const PluginConnectionSchema: z.ZodEffects<z.ZodObject<{
|
|
|
84
84
|
clientSecretEnv?: string | undefined;
|
|
85
85
|
headerNames?: string[] | undefined;
|
|
86
86
|
}>, {
|
|
87
|
-
label: string;
|
|
88
87
|
kind: "oauth2" | "apiKey";
|
|
88
|
+
label: string;
|
|
89
89
|
key: string;
|
|
90
90
|
description?: string | undefined;
|
|
91
91
|
authorizeUrl?: string | undefined;
|
|
@@ -95,8 +95,8 @@ export declare const PluginConnectionSchema: z.ZodEffects<z.ZodObject<{
|
|
|
95
95
|
clientSecretEnv?: string | undefined;
|
|
96
96
|
headerNames?: string[] | undefined;
|
|
97
97
|
}, {
|
|
98
|
-
label: string;
|
|
99
98
|
kind: "oauth2" | "apiKey";
|
|
99
|
+
label: string;
|
|
100
100
|
key: string;
|
|
101
101
|
description?: string | undefined;
|
|
102
102
|
authorizeUrl?: string | undefined;
|
|
@@ -809,12 +809,12 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
809
809
|
values: z.ZodArray<z.ZodString, "many">;
|
|
810
810
|
describe: z.ZodOptional<z.ZodString>;
|
|
811
811
|
}, "strict", z.ZodTypeAny, {
|
|
812
|
-
type: "enum";
|
|
813
812
|
values: string[];
|
|
813
|
+
type: "enum";
|
|
814
814
|
describe?: string | undefined;
|
|
815
815
|
}, {
|
|
816
|
-
type: "enum";
|
|
817
816
|
values: string[];
|
|
817
|
+
type: "enum";
|
|
818
818
|
describe?: string | undefined;
|
|
819
819
|
}>, z.ZodObject<{
|
|
820
820
|
type: z.ZodLiteral<"bool">;
|
|
@@ -856,7 +856,6 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
856
856
|
argv: string[];
|
|
857
857
|
timeoutSeconds?: number | undefined;
|
|
858
858
|
cwd?: string | undefined;
|
|
859
|
-
result?: "json" | "text" | undefined;
|
|
860
859
|
params?: Record<string, "string" | "number" | "int" | "bool" | {
|
|
861
860
|
type: "number" | "int";
|
|
862
861
|
min?: number | undefined;
|
|
@@ -869,13 +868,14 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
869
868
|
allowDash?: boolean | undefined;
|
|
870
869
|
describe?: string | undefined;
|
|
871
870
|
} | {
|
|
872
|
-
type: "enum";
|
|
873
871
|
values: string[];
|
|
872
|
+
type: "enum";
|
|
874
873
|
describe?: string | undefined;
|
|
875
874
|
} | {
|
|
876
875
|
type: "bool";
|
|
877
876
|
describe?: string | undefined;
|
|
878
877
|
}> | undefined;
|
|
878
|
+
result?: "text" | "json" | undefined;
|
|
879
879
|
config?: string[] | undefined;
|
|
880
880
|
describe?: string | undefined;
|
|
881
881
|
env?: Record<string, string> | undefined;
|
|
@@ -891,7 +891,6 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
891
891
|
argv: string[];
|
|
892
892
|
timeoutSeconds?: number | undefined;
|
|
893
893
|
cwd?: string | undefined;
|
|
894
|
-
result?: "json" | "text" | undefined;
|
|
895
894
|
params?: Record<string, "string" | "number" | "int" | "bool" | {
|
|
896
895
|
type: "number" | "int";
|
|
897
896
|
min?: number | undefined;
|
|
@@ -904,13 +903,14 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
904
903
|
allowDash?: boolean | undefined;
|
|
905
904
|
describe?: string | undefined;
|
|
906
905
|
} | {
|
|
907
|
-
type: "enum";
|
|
908
906
|
values: string[];
|
|
907
|
+
type: "enum";
|
|
909
908
|
describe?: string | undefined;
|
|
910
909
|
} | {
|
|
911
910
|
type: "bool";
|
|
912
911
|
describe?: string | undefined;
|
|
913
912
|
}> | undefined;
|
|
913
|
+
result?: "text" | "json" | undefined;
|
|
914
914
|
config?: string[] | undefined;
|
|
915
915
|
describe?: string | undefined;
|
|
916
916
|
env?: Record<string, string> | undefined;
|
|
@@ -1004,7 +1004,6 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1004
1004
|
argv: string[];
|
|
1005
1005
|
timeoutSeconds?: number | undefined;
|
|
1006
1006
|
cwd?: string | undefined;
|
|
1007
|
-
result?: "json" | "text" | undefined;
|
|
1008
1007
|
params?: Record<string, "string" | "number" | "int" | "bool" | {
|
|
1009
1008
|
type: "number" | "int";
|
|
1010
1009
|
min?: number | undefined;
|
|
@@ -1017,13 +1016,14 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1017
1016
|
allowDash?: boolean | undefined;
|
|
1018
1017
|
describe?: string | undefined;
|
|
1019
1018
|
} | {
|
|
1020
|
-
type: "enum";
|
|
1021
1019
|
values: string[];
|
|
1020
|
+
type: "enum";
|
|
1022
1021
|
describe?: string | undefined;
|
|
1023
1022
|
} | {
|
|
1024
1023
|
type: "bool";
|
|
1025
1024
|
describe?: string | undefined;
|
|
1026
1025
|
}> | undefined;
|
|
1026
|
+
result?: "text" | "json" | undefined;
|
|
1027
1027
|
config?: string[] | undefined;
|
|
1028
1028
|
describe?: string | undefined;
|
|
1029
1029
|
env?: Record<string, string> | undefined;
|
|
@@ -1063,7 +1063,6 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1063
1063
|
argv: string[];
|
|
1064
1064
|
timeoutSeconds?: number | undefined;
|
|
1065
1065
|
cwd?: string | undefined;
|
|
1066
|
-
result?: "json" | "text" | undefined;
|
|
1067
1066
|
params?: Record<string, "string" | "number" | "int" | "bool" | {
|
|
1068
1067
|
type: "number" | "int";
|
|
1069
1068
|
min?: number | undefined;
|
|
@@ -1076,13 +1075,14 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1076
1075
|
allowDash?: boolean | undefined;
|
|
1077
1076
|
describe?: string | undefined;
|
|
1078
1077
|
} | {
|
|
1079
|
-
type: "enum";
|
|
1080
1078
|
values: string[];
|
|
1079
|
+
type: "enum";
|
|
1081
1080
|
describe?: string | undefined;
|
|
1082
1081
|
} | {
|
|
1083
1082
|
type: "bool";
|
|
1084
1083
|
describe?: string | undefined;
|
|
1085
1084
|
}> | undefined;
|
|
1085
|
+
result?: "text" | "json" | undefined;
|
|
1086
1086
|
config?: string[] | undefined;
|
|
1087
1087
|
describe?: string | undefined;
|
|
1088
1088
|
env?: Record<string, string> | undefined;
|
|
@@ -1122,7 +1122,6 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1122
1122
|
argv: string[];
|
|
1123
1123
|
timeoutSeconds?: number | undefined;
|
|
1124
1124
|
cwd?: string | undefined;
|
|
1125
|
-
result?: "json" | "text" | undefined;
|
|
1126
1125
|
params?: Record<string, "string" | "number" | "int" | "bool" | {
|
|
1127
1126
|
type: "number" | "int";
|
|
1128
1127
|
min?: number | undefined;
|
|
@@ -1135,13 +1134,14 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1135
1134
|
allowDash?: boolean | undefined;
|
|
1136
1135
|
describe?: string | undefined;
|
|
1137
1136
|
} | {
|
|
1138
|
-
type: "enum";
|
|
1139
1137
|
values: string[];
|
|
1138
|
+
type: "enum";
|
|
1140
1139
|
describe?: string | undefined;
|
|
1141
1140
|
} | {
|
|
1142
1141
|
type: "bool";
|
|
1143
1142
|
describe?: string | undefined;
|
|
1144
1143
|
}> | undefined;
|
|
1144
|
+
result?: "text" | "json" | undefined;
|
|
1145
1145
|
config?: string[] | undefined;
|
|
1146
1146
|
describe?: string | undefined;
|
|
1147
1147
|
env?: Record<string, string> | undefined;
|
|
@@ -1181,7 +1181,6 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1181
1181
|
argv: string[];
|
|
1182
1182
|
timeoutSeconds?: number | undefined;
|
|
1183
1183
|
cwd?: string | undefined;
|
|
1184
|
-
result?: "json" | "text" | undefined;
|
|
1185
1184
|
params?: Record<string, "string" | "number" | "int" | "bool" | {
|
|
1186
1185
|
type: "number" | "int";
|
|
1187
1186
|
min?: number | undefined;
|
|
@@ -1194,13 +1193,14 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1194
1193
|
allowDash?: boolean | undefined;
|
|
1195
1194
|
describe?: string | undefined;
|
|
1196
1195
|
} | {
|
|
1197
|
-
type: "enum";
|
|
1198
1196
|
values: string[];
|
|
1197
|
+
type: "enum";
|
|
1199
1198
|
describe?: string | undefined;
|
|
1200
1199
|
} | {
|
|
1201
1200
|
type: "bool";
|
|
1202
1201
|
describe?: string | undefined;
|
|
1203
1202
|
}> | undefined;
|
|
1203
|
+
result?: "text" | "json" | undefined;
|
|
1204
1204
|
config?: string[] | undefined;
|
|
1205
1205
|
describe?: string | undefined;
|
|
1206
1206
|
env?: Record<string, string> | undefined;
|
|
@@ -1255,8 +1255,8 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1255
1255
|
/** apiKey: header NAMES the plugin will send (never values). */
|
|
1256
1256
|
headerNames: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1257
1257
|
}, "strict", z.ZodTypeAny, {
|
|
1258
|
-
label: string;
|
|
1259
1258
|
kind: "oauth2" | "apiKey";
|
|
1259
|
+
label: string;
|
|
1260
1260
|
key: string;
|
|
1261
1261
|
description?: string | undefined;
|
|
1262
1262
|
authorizeUrl?: string | undefined;
|
|
@@ -1266,8 +1266,8 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1266
1266
|
clientSecretEnv?: string | undefined;
|
|
1267
1267
|
headerNames?: string[] | undefined;
|
|
1268
1268
|
}, {
|
|
1269
|
-
label: string;
|
|
1270
1269
|
kind: "oauth2" | "apiKey";
|
|
1270
|
+
label: string;
|
|
1271
1271
|
key: string;
|
|
1272
1272
|
description?: string | undefined;
|
|
1273
1273
|
authorizeUrl?: string | undefined;
|
|
@@ -1277,8 +1277,8 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1277
1277
|
clientSecretEnv?: string | undefined;
|
|
1278
1278
|
headerNames?: string[] | undefined;
|
|
1279
1279
|
}>, {
|
|
1280
|
-
label: string;
|
|
1281
1280
|
kind: "oauth2" | "apiKey";
|
|
1281
|
+
label: string;
|
|
1282
1282
|
key: string;
|
|
1283
1283
|
description?: string | undefined;
|
|
1284
1284
|
authorizeUrl?: string | undefined;
|
|
@@ -1288,8 +1288,8 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1288
1288
|
clientSecretEnv?: string | undefined;
|
|
1289
1289
|
headerNames?: string[] | undefined;
|
|
1290
1290
|
}, {
|
|
1291
|
-
label: string;
|
|
1292
1291
|
kind: "oauth2" | "apiKey";
|
|
1292
|
+
label: string;
|
|
1293
1293
|
key: string;
|
|
1294
1294
|
description?: string | undefined;
|
|
1295
1295
|
authorizeUrl?: string | undefined;
|
|
@@ -1453,13 +1453,13 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1453
1453
|
events: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1454
1454
|
models: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1455
1455
|
}, "strict", z.ZodTypeAny, {
|
|
1456
|
+
models?: string[] | undefined;
|
|
1456
1457
|
tools?: string[] | undefined;
|
|
1457
1458
|
events?: string[] | undefined;
|
|
1458
|
-
models?: string[] | undefined;
|
|
1459
1459
|
}, {
|
|
1460
|
+
models?: string[] | undefined;
|
|
1460
1461
|
tools?: string[] | undefined;
|
|
1461
1462
|
events?: string[] | undefined;
|
|
1462
|
-
models?: string[] | undefined;
|
|
1463
1463
|
}>>>;
|
|
1464
1464
|
/**
|
|
1465
1465
|
* The app's realtime TOPICS, and who hears each (forge-sdk-spec-and-tests
|
|
@@ -1552,9 +1552,9 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1552
1552
|
}>>>;
|
|
1553
1553
|
}, "strict", z.ZodTypeAny, {
|
|
1554
1554
|
name: string;
|
|
1555
|
+
id: string;
|
|
1555
1556
|
version: string;
|
|
1556
1557
|
applicationType: string;
|
|
1557
|
-
id: string;
|
|
1558
1558
|
description: string;
|
|
1559
1559
|
scopes: string[];
|
|
1560
1560
|
ops: string[] | Record<string, {
|
|
@@ -1578,8 +1578,8 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1578
1578
|
}[];
|
|
1579
1579
|
workspaceTools: string[];
|
|
1580
1580
|
connections: {
|
|
1581
|
-
label: string;
|
|
1582
1581
|
kind: "oauth2" | "apiKey";
|
|
1582
|
+
label: string;
|
|
1583
1583
|
key: string;
|
|
1584
1584
|
description?: string | undefined;
|
|
1585
1585
|
authorizeUrl?: string | undefined;
|
|
@@ -1603,7 +1603,6 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1603
1603
|
argv: string[];
|
|
1604
1604
|
timeoutSeconds?: number | undefined;
|
|
1605
1605
|
cwd?: string | undefined;
|
|
1606
|
-
result?: "json" | "text" | undefined;
|
|
1607
1606
|
params?: Record<string, "string" | "number" | "int" | "bool" | {
|
|
1608
1607
|
type: "number" | "int";
|
|
1609
1608
|
min?: number | undefined;
|
|
@@ -1616,13 +1615,14 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1616
1615
|
allowDash?: boolean | undefined;
|
|
1617
1616
|
describe?: string | undefined;
|
|
1618
1617
|
} | {
|
|
1619
|
-
type: "enum";
|
|
1620
1618
|
values: string[];
|
|
1619
|
+
type: "enum";
|
|
1621
1620
|
describe?: string | undefined;
|
|
1622
1621
|
} | {
|
|
1623
1622
|
type: "bool";
|
|
1624
1623
|
describe?: string | undefined;
|
|
1625
1624
|
}> | undefined;
|
|
1625
|
+
result?: "text" | "json" | undefined;
|
|
1626
1626
|
config?: string[] | undefined;
|
|
1627
1627
|
describe?: string | undefined;
|
|
1628
1628
|
env?: Record<string, string> | undefined;
|
|
@@ -1716,9 +1716,9 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1716
1716
|
optional?: boolean | undefined;
|
|
1717
1717
|
}> | undefined;
|
|
1718
1718
|
provides?: Record<string, {
|
|
1719
|
+
models?: string[] | undefined;
|
|
1719
1720
|
tools?: string[] | undefined;
|
|
1720
1721
|
events?: string[] | undefined;
|
|
1721
|
-
models?: string[] | undefined;
|
|
1722
1722
|
}> | undefined;
|
|
1723
1723
|
channel?: {
|
|
1724
1724
|
topics: Record<string, {
|
|
@@ -1741,9 +1741,9 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1741
1741
|
}> | undefined;
|
|
1742
1742
|
}, {
|
|
1743
1743
|
name: string;
|
|
1744
|
+
id: string;
|
|
1744
1745
|
version: string;
|
|
1745
1746
|
applicationType: string;
|
|
1746
|
-
id: string;
|
|
1747
1747
|
description: string;
|
|
1748
1748
|
manifestVersion: 1;
|
|
1749
1749
|
entry: string;
|
|
@@ -1752,7 +1752,6 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1752
1752
|
argv: string[];
|
|
1753
1753
|
timeoutSeconds?: number | undefined;
|
|
1754
1754
|
cwd?: string | undefined;
|
|
1755
|
-
result?: "json" | "text" | undefined;
|
|
1756
1755
|
params?: Record<string, "string" | "number" | "int" | "bool" | {
|
|
1757
1756
|
type: "number" | "int";
|
|
1758
1757
|
min?: number | undefined;
|
|
@@ -1765,13 +1764,14 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1765
1764
|
allowDash?: boolean | undefined;
|
|
1766
1765
|
describe?: string | undefined;
|
|
1767
1766
|
} | {
|
|
1768
|
-
type: "enum";
|
|
1769
1767
|
values: string[];
|
|
1768
|
+
type: "enum";
|
|
1770
1769
|
describe?: string | undefined;
|
|
1771
1770
|
} | {
|
|
1772
1771
|
type: "bool";
|
|
1773
1772
|
describe?: string | undefined;
|
|
1774
1773
|
}> | undefined;
|
|
1774
|
+
result?: "text" | "json" | undefined;
|
|
1775
1775
|
config?: string[] | undefined;
|
|
1776
1776
|
describe?: string | undefined;
|
|
1777
1777
|
env?: Record<string, string> | undefined;
|
|
@@ -1874,8 +1874,8 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1874
1874
|
} | undefined;
|
|
1875
1875
|
workspaceTools?: string[] | undefined;
|
|
1876
1876
|
connections?: {
|
|
1877
|
-
label: string;
|
|
1878
1877
|
kind: "oauth2" | "apiKey";
|
|
1878
|
+
label: string;
|
|
1879
1879
|
key: string;
|
|
1880
1880
|
description?: string | undefined;
|
|
1881
1881
|
authorizeUrl?: string | undefined;
|
|
@@ -1905,9 +1905,9 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1905
1905
|
optional?: boolean | undefined;
|
|
1906
1906
|
}> | undefined;
|
|
1907
1907
|
provides?: Record<string, {
|
|
1908
|
+
models?: string[] | undefined;
|
|
1908
1909
|
tools?: string[] | undefined;
|
|
1909
1910
|
events?: string[] | undefined;
|
|
1910
|
-
models?: string[] | undefined;
|
|
1911
1911
|
}> | undefined;
|
|
1912
1912
|
channel?: {
|
|
1913
1913
|
topics: Record<string, {
|
|
@@ -1930,9 +1930,9 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1930
1930
|
}> | undefined;
|
|
1931
1931
|
}>, {
|
|
1932
1932
|
name: string;
|
|
1933
|
+
id: string;
|
|
1933
1934
|
version: string;
|
|
1934
1935
|
applicationType: string;
|
|
1935
|
-
id: string;
|
|
1936
1936
|
description: string;
|
|
1937
1937
|
scopes: string[];
|
|
1938
1938
|
ops: string[] | Record<string, {
|
|
@@ -1956,8 +1956,8 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1956
1956
|
}[];
|
|
1957
1957
|
workspaceTools: string[];
|
|
1958
1958
|
connections: {
|
|
1959
|
-
label: string;
|
|
1960
1959
|
kind: "oauth2" | "apiKey";
|
|
1960
|
+
label: string;
|
|
1961
1961
|
key: string;
|
|
1962
1962
|
description?: string | undefined;
|
|
1963
1963
|
authorizeUrl?: string | undefined;
|
|
@@ -1981,7 +1981,6 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1981
1981
|
argv: string[];
|
|
1982
1982
|
timeoutSeconds?: number | undefined;
|
|
1983
1983
|
cwd?: string | undefined;
|
|
1984
|
-
result?: "json" | "text" | undefined;
|
|
1985
1984
|
params?: Record<string, "string" | "number" | "int" | "bool" | {
|
|
1986
1985
|
type: "number" | "int";
|
|
1987
1986
|
min?: number | undefined;
|
|
@@ -1994,13 +1993,14 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1994
1993
|
allowDash?: boolean | undefined;
|
|
1995
1994
|
describe?: string | undefined;
|
|
1996
1995
|
} | {
|
|
1997
|
-
type: "enum";
|
|
1998
1996
|
values: string[];
|
|
1997
|
+
type: "enum";
|
|
1999
1998
|
describe?: string | undefined;
|
|
2000
1999
|
} | {
|
|
2001
2000
|
type: "bool";
|
|
2002
2001
|
describe?: string | undefined;
|
|
2003
2002
|
}> | undefined;
|
|
2003
|
+
result?: "text" | "json" | undefined;
|
|
2004
2004
|
config?: string[] | undefined;
|
|
2005
2005
|
describe?: string | undefined;
|
|
2006
2006
|
env?: Record<string, string> | undefined;
|
|
@@ -2094,9 +2094,9 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
2094
2094
|
optional?: boolean | undefined;
|
|
2095
2095
|
}> | undefined;
|
|
2096
2096
|
provides?: Record<string, {
|
|
2097
|
+
models?: string[] | undefined;
|
|
2097
2098
|
tools?: string[] | undefined;
|
|
2098
2099
|
events?: string[] | undefined;
|
|
2099
|
-
models?: string[] | undefined;
|
|
2100
2100
|
}> | undefined;
|
|
2101
2101
|
channel?: {
|
|
2102
2102
|
topics: Record<string, {
|
|
@@ -2119,9 +2119,9 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
2119
2119
|
}> | undefined;
|
|
2120
2120
|
}, {
|
|
2121
2121
|
name: string;
|
|
2122
|
+
id: string;
|
|
2122
2123
|
version: string;
|
|
2123
2124
|
applicationType: string;
|
|
2124
|
-
id: string;
|
|
2125
2125
|
description: string;
|
|
2126
2126
|
manifestVersion: 1;
|
|
2127
2127
|
entry: string;
|
|
@@ -2130,7 +2130,6 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
2130
2130
|
argv: string[];
|
|
2131
2131
|
timeoutSeconds?: number | undefined;
|
|
2132
2132
|
cwd?: string | undefined;
|
|
2133
|
-
result?: "json" | "text" | undefined;
|
|
2134
2133
|
params?: Record<string, "string" | "number" | "int" | "bool" | {
|
|
2135
2134
|
type: "number" | "int";
|
|
2136
2135
|
min?: number | undefined;
|
|
@@ -2143,13 +2142,14 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
2143
2142
|
allowDash?: boolean | undefined;
|
|
2144
2143
|
describe?: string | undefined;
|
|
2145
2144
|
} | {
|
|
2146
|
-
type: "enum";
|
|
2147
2145
|
values: string[];
|
|
2146
|
+
type: "enum";
|
|
2148
2147
|
describe?: string | undefined;
|
|
2149
2148
|
} | {
|
|
2150
2149
|
type: "bool";
|
|
2151
2150
|
describe?: string | undefined;
|
|
2152
2151
|
}> | undefined;
|
|
2152
|
+
result?: "text" | "json" | undefined;
|
|
2153
2153
|
config?: string[] | undefined;
|
|
2154
2154
|
describe?: string | undefined;
|
|
2155
2155
|
env?: Record<string, string> | undefined;
|
|
@@ -2252,8 +2252,8 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
2252
2252
|
} | undefined;
|
|
2253
2253
|
workspaceTools?: string[] | undefined;
|
|
2254
2254
|
connections?: {
|
|
2255
|
-
label: string;
|
|
2256
2255
|
kind: "oauth2" | "apiKey";
|
|
2256
|
+
label: string;
|
|
2257
2257
|
key: string;
|
|
2258
2258
|
description?: string | undefined;
|
|
2259
2259
|
authorizeUrl?: string | undefined;
|
|
@@ -2283,9 +2283,9 @@ export declare const PluginManifestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
2283
2283
|
optional?: boolean | undefined;
|
|
2284
2284
|
}> | undefined;
|
|
2285
2285
|
provides?: Record<string, {
|
|
2286
|
+
models?: string[] | undefined;
|
|
2286
2287
|
tools?: string[] | undefined;
|
|
2287
2288
|
events?: string[] | undefined;
|
|
2288
|
-
models?: string[] | undefined;
|
|
2289
2289
|
}> | undefined;
|
|
2290
2290
|
channel?: {
|
|
2291
2291
|
topics: Record<string, {
|
package/dist/react.d.ts
CHANGED
|
@@ -67,6 +67,15 @@ export interface WorkspaceNav {
|
|
|
67
67
|
* already on.
|
|
68
68
|
*/
|
|
69
69
|
export declare function useWorkspaceNav(): WorkspaceNav;
|
|
70
|
+
/** A place inside an app, as named by whoever asks to open it: `{ thread: "…" }`, `{ campaign: "…" }`. */
|
|
71
|
+
export type AppNavTarget = Record<string, string>;
|
|
72
|
+
/**
|
|
73
|
+
* "Open THIS inside the app": the platform's tasks pane, a link chip or a recall hit asks for a
|
|
74
|
+
* place inside this app instance (the keys are the app's own — say which in your tool and task
|
|
75
|
+
* descriptions). `onTarget` runs with the target waiting when the app mounts, and with each one
|
|
76
|
+
* asked for while it is on screen. Open it and select it; an unknown key does nothing.
|
|
77
|
+
*/
|
|
78
|
+
export declare function useAppNav(_nodeId: string, _onTarget: (target: AppNavTarget) => void): void;
|
|
70
79
|
import type { FileEntry, FileListOptions, FileRef, FileSource } from "./files.js";
|
|
71
80
|
import type { TransferSnapshot } from "./transfers.js";
|
|
72
81
|
import type { LabelPoint, LabelShape } from "./labelme.js";
|
package/dist/react.js
CHANGED
|
@@ -33,6 +33,15 @@ export function useWorkspaceTools(_identity) {
|
|
|
33
33
|
export function useWorkspaceNav() {
|
|
34
34
|
return hostOnly("useWorkspaceNav");
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* "Open THIS inside the app": the platform's tasks pane, a link chip or a recall hit asks for a
|
|
38
|
+
* place inside this app instance (the keys are the app's own — say which in your tool and task
|
|
39
|
+
* descriptions). `onTarget` runs with the target waiting when the app mounts, and with each one
|
|
40
|
+
* asked for while it is on screen. Open it and select it; an unknown key does nothing.
|
|
41
|
+
*/
|
|
42
|
+
export function useAppNav(_nodeId, _onTarget) {
|
|
43
|
+
return hostOnly("useAppNav");
|
|
44
|
+
}
|
|
36
45
|
/** A files call from the UI refused — `kind` is the FileSourceErrorKind when the source said why. */
|
|
37
46
|
export class FilesBrowseError extends Error {
|
|
38
47
|
kind;
|
package/dist/server.d.ts
CHANGED
|
@@ -208,8 +208,12 @@ export interface PluginServerModule {
|
|
|
208
208
|
ops?: Record<string, PluginOpHandler>;
|
|
209
209
|
/** routeName → handler, for names declared in plugin.json `routes`. */
|
|
210
210
|
routes?: Record<string, PluginRouteHandler>;
|
|
211
|
-
/**
|
|
212
|
-
|
|
211
|
+
/**
|
|
212
|
+
* key → producer, for keys declared in plugin.json `fileProducers`: the app's own bytes as a
|
|
213
|
+
* transfer source. Each producer keeps its own key type (`PluginFileProducer<MyKey>`, an
|
|
214
|
+
* interface or a type) — the platform hands `open` the key the transfer item named.
|
|
215
|
+
*/
|
|
216
|
+
fileProducers?: Record<string, PluginFileProducer<any>>;
|
|
213
217
|
}
|
|
214
218
|
export type PluginConnectionCredentials = {
|
|
215
219
|
kind: "oauth2";
|
|
@@ -578,8 +582,13 @@ export interface EmitPluginAppEventArgs {
|
|
|
578
582
|
eventData: Record<string, unknown>;
|
|
579
583
|
}
|
|
580
584
|
/**
|
|
581
|
-
* Read one app's state folded to head, by nodeId — server truth for an op
|
|
582
|
-
*
|
|
585
|
+
* Read one app's state folded to head, by nodeId — server truth for an op, route,
|
|
586
|
+
* task or webhook. It reads for the app instance of the call the platform is
|
|
587
|
+
* running: your own app and other instances of its type in your workspace; another
|
|
588
|
+
* app type only when plugin.json `workspaceTools` grants a tool of that type (the
|
|
589
|
+
* refusal names the line to add). Null when no such app exists — an app in another
|
|
590
|
+
* workspace is null too. A webhook (it runs for no instance) finds only instances
|
|
591
|
+
* of its own type. Outside a running call it throws. HOST-ONLY.
|
|
583
592
|
*/
|
|
584
593
|
export declare function readAppState(_nodeId: string): Promise<{
|
|
585
594
|
nodeId: string;
|
|
@@ -658,6 +667,67 @@ export declare function mintRouteToken(_ctx: {
|
|
|
658
667
|
ttlSeconds?: number;
|
|
659
668
|
label?: string;
|
|
660
669
|
}): Promise<RouteTokenGrant>;
|
|
670
|
+
/** A question for the person (questions(ctx).ask). */
|
|
671
|
+
export interface AppQuestion {
|
|
672
|
+
/** Stable per question within this app instance: asking twice with one key is one question. */
|
|
673
|
+
key: string;
|
|
674
|
+
question: string;
|
|
675
|
+
/** 1–4 answers the bell offers as buttons; without them the person types. */
|
|
676
|
+
options?: string[];
|
|
677
|
+
/** Context the bell shows under the question (≤1500 characters as JSON). */
|
|
678
|
+
details?: Record<string, unknown>;
|
|
679
|
+
/** Where the bell's Open button takes the person: the app hears `{ [kind]: key }` through useAppNav. */
|
|
680
|
+
open?: {
|
|
681
|
+
kind: string;
|
|
682
|
+
key: string;
|
|
683
|
+
label?: string;
|
|
684
|
+
};
|
|
685
|
+
/** The app's own op that takes the answer, called as the person answering with `{ ...args, answer }`. */
|
|
686
|
+
answer: {
|
|
687
|
+
op: string;
|
|
688
|
+
args?: Record<string, unknown>;
|
|
689
|
+
};
|
|
690
|
+
expiresInSeconds?: number;
|
|
691
|
+
}
|
|
692
|
+
export interface Questions {
|
|
693
|
+
ask(q: AppQuestion): Promise<{
|
|
694
|
+
questionId: string;
|
|
695
|
+
created: boolean;
|
|
696
|
+
}>;
|
|
697
|
+
/** The app settled it itself (answered on its own screen, the asker ended): the bell's row closes. */
|
|
698
|
+
settle(key: string, outcome: {
|
|
699
|
+
answer: string;
|
|
700
|
+
} | {
|
|
701
|
+
cancelled: true;
|
|
702
|
+
}): Promise<void>;
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* THE PLATFORM'S QUESTIONS BELL. A question an app needs the person to answer
|
|
706
|
+
* (an agent waiting on a decision) reaches them wherever they are — the bell,
|
|
707
|
+
* on every workspace — not only when they open the app:
|
|
708
|
+
*
|
|
709
|
+
* await questions(ctx).ask({
|
|
710
|
+
* key: `thread:${threadId}:${questionId}`,
|
|
711
|
+
* question: "Accept 12 % off if they order 500?",
|
|
712
|
+
* options: ["Yes", "No"],
|
|
713
|
+
* open: { kind: "thread", key: threadId, label: "Open email thread" },
|
|
714
|
+
* answer: { op: "answer_question", args: { threadId, questionId } },
|
|
715
|
+
* });
|
|
716
|
+
*
|
|
717
|
+
* Answering in the bell calls `answer.op` with `{ ...args, answer }` as the
|
|
718
|
+
* person who answered (their access, the op's own rules); an `{ ok: false }`
|
|
719
|
+
* reply closes the row and shows the app's reason. When the app takes the
|
|
720
|
+
* answer on its own screen, `settle(key, { answer })` closes the row without a
|
|
721
|
+
* call back. HOST-ONLY; the Forge box keeps no bell (ask answers `created: false`).
|
|
722
|
+
*/
|
|
723
|
+
export declare function questions(_ctx: {
|
|
724
|
+
pluginId: string;
|
|
725
|
+
workspaceId: string;
|
|
726
|
+
nodeId: string;
|
|
727
|
+
viewer?: {
|
|
728
|
+
userId: string | null;
|
|
729
|
+
};
|
|
730
|
+
}): Questions;
|
|
661
731
|
/**
|
|
662
732
|
* PARTS OF THE APP THAT RUN ON THE PERSON'S COMPUTER (plugin-device-arm.md).
|
|
663
733
|
* The app declares its commands in plugin.json `device.commands`; the owner
|
package/dist/server.js
CHANGED
|
@@ -202,8 +202,13 @@ export function removeAppRole(_ctx, _name) {
|
|
|
202
202
|
return hostOnly("removeAppRole");
|
|
203
203
|
}
|
|
204
204
|
/**
|
|
205
|
-
* Read one app's state folded to head, by nodeId — server truth for an op
|
|
206
|
-
*
|
|
205
|
+
* Read one app's state folded to head, by nodeId — server truth for an op, route,
|
|
206
|
+
* task or webhook. It reads for the app instance of the call the platform is
|
|
207
|
+
* running: your own app and other instances of its type in your workspace; another
|
|
208
|
+
* app type only when plugin.json `workspaceTools` grants a tool of that type (the
|
|
209
|
+
* refusal names the line to add). Null when no such app exists — an app in another
|
|
210
|
+
* workspace is null too. A webhook (it runs for no instance) finds only instances
|
|
211
|
+
* of its own type. Outside a running call it throws. HOST-ONLY.
|
|
207
212
|
*/
|
|
208
213
|
export function readAppState(_nodeId) {
|
|
209
214
|
return hostOnly("readAppState");
|
|
@@ -256,6 +261,28 @@ export function renderChartImage(_ctx, _args) {
|
|
|
256
261
|
export function mintRouteToken(_ctx, _args) {
|
|
257
262
|
return hostOnly("mintRouteToken");
|
|
258
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* THE PLATFORM'S QUESTIONS BELL. A question an app needs the person to answer
|
|
266
|
+
* (an agent waiting on a decision) reaches them wherever they are — the bell,
|
|
267
|
+
* on every workspace — not only when they open the app:
|
|
268
|
+
*
|
|
269
|
+
* await questions(ctx).ask({
|
|
270
|
+
* key: `thread:${threadId}:${questionId}`,
|
|
271
|
+
* question: "Accept 12 % off if they order 500?",
|
|
272
|
+
* options: ["Yes", "No"],
|
|
273
|
+
* open: { kind: "thread", key: threadId, label: "Open email thread" },
|
|
274
|
+
* answer: { op: "answer_question", args: { threadId, questionId } },
|
|
275
|
+
* });
|
|
276
|
+
*
|
|
277
|
+
* Answering in the bell calls `answer.op` with `{ ...args, answer }` as the
|
|
278
|
+
* person who answered (their access, the op's own rules); an `{ ok: false }`
|
|
279
|
+
* reply closes the row and shows the app's reason. When the app takes the
|
|
280
|
+
* answer on its own screen, `settle(key, { answer })` closes the row without a
|
|
281
|
+
* call back. HOST-ONLY; the Forge box keeps no bell (ask answers `created: false`).
|
|
282
|
+
*/
|
|
283
|
+
export function questions(_ctx) {
|
|
284
|
+
return hostOnly("questions");
|
|
285
|
+
}
|
|
259
286
|
/**
|
|
260
287
|
* PARTS OF THE APP THAT RUN ON THE PERSON'S COMPUTER (plugin-device-arm.md).
|
|
261
288
|
* The app declares its commands in plugin.json `device.commands`; the owner
|
package/dist/types.d.ts
CHANGED
|
@@ -106,6 +106,15 @@ export interface EventDefinition<StateType extends ApplicationIdentifier> {
|
|
|
106
106
|
triggerMeta?: TriggerMeta;
|
|
107
107
|
sideEffect?: EventSideEffect;
|
|
108
108
|
permission?: "user_exclusive";
|
|
109
|
+
/**
|
|
110
|
+
* WHO MAY APPEND IT. `"server"`: this event records something only the app's own server code
|
|
111
|
+
* knows — a message sent, a sync's result, a model's output, a payment. It is appended by the
|
|
112
|
+
* app's ops, routes, tasks and webhooks (and the platform), never by a client: the browser's
|
|
113
|
+
* append and WAL doors and the PAT/SDK dispatch routes refuse it, so nobody can plant a "sent"
|
|
114
|
+
* that was never sent or a sync that never ran (the platform's mail requirements, KD-120). Absent: any writer
|
|
115
|
+
* with access to the app may append it, as before.
|
|
116
|
+
*/
|
|
117
|
+
origin?: "server";
|
|
109
118
|
conflictPolicy?: "mark" | "silent";
|
|
110
119
|
/** The sub-items (e.g. block ids) a partial write touches — two devices
|
|
111
120
|
* writing different sub-items of one item merge without a conflict. */
|
|
@@ -88,13 +88,20 @@ snapshot baselines and the durability layers. Every shipped plugin and the scaff
|
|
|
88
88
|
|
|
89
89
|
## Events only the server emits
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
An event that records something only your server code knows — a letter sent, a sync's result, a
|
|
92
|
+
model's answer, a payment — says so with `origin: "server"`:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
{ eventName: "mail_sent", type: EventTypes.Client, origin: "server", dataCreator, processor }
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Your ops, routes, tasks and webhooks append it as usual (`ctx.emit`, a task's `dispatchEvent`).
|
|
99
|
+
Every door a CLIENT's event enters by refuses it — the browser's appends and offline queue, and the
|
|
100
|
+
PAT / SDK / MCP dispatch routes — so nobody with write access can plant a "sent" that was never
|
|
101
|
+
sent or a sync that never ran. Your UI can still predict it for an optimistic click (run the
|
|
102
|
+
processor locally); it just never dispatches it. `EventTypes` has no server type for this
|
|
103
|
+
(`Client`, `Workflow`, `Workspace` only — an earlier version of this page named `EventTypes.Server`,
|
|
104
|
+
which does not exist); `origin` is the switch. The processor still obeys the three rules.
|
|
98
105
|
|
|
99
106
|
## Durability you get for free
|
|
100
107
|
|
package/docs/04-tools.md
CHANGED
|
@@ -100,6 +100,33 @@ a `PluginCallError` carrying the platform's `code` (`forbidden`, `login-required
|
|
|
100
100
|
pass it to `useSignInWall().raise(err)` in the UI and a `login-required` becomes the sign-in wall
|
|
101
101
|
instead of an error. Relay any other error's message; never swallow it.
|
|
102
102
|
|
|
103
|
+
## Waiting inside a network run — `mailWaitDirective`
|
|
104
|
+
|
|
105
|
+
Inside an agent network run (`runCtx` is the fifth argument of `toolkitCreator`; absent in chat and
|
|
106
|
+
voice) a tool can PAUSE the run until mail arrives — minutes or days, nothing running — with the
|
|
107
|
+
platform's own wait kernel:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { mailWaitDirective } from "esoul-sdk";
|
|
111
|
+
|
|
112
|
+
execute: async (args) => {
|
|
113
|
+
if (!runCtx) return "Only inside an agent network run.";
|
|
114
|
+
if (runCtx.isWaitDirectiveAlreadyCreatedThisStep()) return "One wait per turn.";
|
|
115
|
+
eventCallback(mailWaitDirective(runCtx, {
|
|
116
|
+
workspaceId, inboxNodeId: identifier.nodeId, inboxName: identifier.instanceName,
|
|
117
|
+
toolName: `wait_for_email_${base}`, threadId: args.threadId,
|
|
118
|
+
afterTimestamp, // the newest message the agent has already seen
|
|
119
|
+
directiveId, // stable for a retried call
|
|
120
|
+
}));
|
|
121
|
+
runCtx.setWaitDirectiveCreatedThisStep();
|
|
122
|
+
return "Waiting…";
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The run wakes on `workspace/email.message_arrived` for this inbox (the platform sends it for the
|
|
127
|
+
Gmail app's live mail) and first checks the inbox's folded `messages` for an arrival newer than
|
|
128
|
+
`afterTimestamp`, so a reply that landed before the wait is not missed.
|
|
129
|
+
|
|
103
130
|
## Calling other apps
|
|
104
131
|
|
|
105
132
|
From the UI: `useWorkspaceTools()` (docs/05). From server code: `callWorkspaceTool` (docs/06).
|
package/docs/05-ui.md
CHANGED
|
@@ -165,6 +165,26 @@ Reload in place, without a skeleton: a screen that flashes every time the assist
|
|
|
165
165
|
reads as broken. Check it in the workbench: open the preview, call one of your write tools from the
|
|
166
166
|
board (or `esoul-forge tool …`), and watch the view change within a few seconds, without a reload.
|
|
167
167
|
|
|
168
|
+
## Opened from outside: a place inside your app
|
|
169
|
+
|
|
170
|
+
The platform's tasks pane (and, as they adopt it, link chips and memory hits) can open a place
|
|
171
|
+
INSIDE your app — a conversation, a campaign, a page — not just the app. It names the place with
|
|
172
|
+
keys you choose; you hear it with `useAppNav`:
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
import { useAppNav } from "esoul-sdk/react";
|
|
176
|
+
|
|
177
|
+
useAppNav(nodeId, (target) => {
|
|
178
|
+
if (target.thread) openThread(target.thread);
|
|
179
|
+
else if (target.campaign) openCampaign(target.campaign);
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`onTarget` runs with the place waiting when the app mounts (declare it after any effect that
|
|
184
|
+
restores a remembered view, so the request wins) and with each one asked for while the app is on
|
|
185
|
+
screen. An unknown key does nothing. Name the keys in your task descriptions so the platform can
|
|
186
|
+
point at them.
|
|
187
|
+
|
|
168
188
|
## Cross-app from the UI
|
|
169
189
|
|
|
170
190
|
```ts
|
package/docs/06-server.md
CHANGED
|
@@ -61,6 +61,31 @@ One app, folded to head: `{ nodeId, workspaceId, applicationType, foldedSeq, sta
|
|
|
61
61
|
when absent. Use it for your own instance and, with care, for other apps in the same workspace.
|
|
62
62
|
Never a raw database read — the import wall refuses `prisma` and the state column lags the log.
|
|
63
63
|
|
|
64
|
+
## Asking the person — `questions(ctx)`
|
|
65
|
+
|
|
66
|
+
A question your app needs answered (an agent waiting on a decision) goes to the platform's
|
|
67
|
+
questions bell, which the person sees on every workspace — not only when your app is open:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { questions } from "esoul-sdk/server";
|
|
71
|
+
|
|
72
|
+
await questions(ctx).ask({
|
|
73
|
+
key: `thread:${threadId}:${questionId}`, // one question per key: a replayed ask is the same one
|
|
74
|
+
question: "Accept 12 % off if they order 500?",
|
|
75
|
+
options: ["Yes", "No"], // 1–4 → buttons; without them the person types
|
|
76
|
+
open: { kind: "thread", key: threadId, label: "Open email thread" },
|
|
77
|
+
answer: { op: "answer_question", args: { threadId, questionId, via: "bell" } },
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- Answered in the bell, the platform calls **your own op** (`answer.op`, one of your declared ops)
|
|
82
|
+
with `{ ...args, answer }`, as the person who answered — their access, your op's rules. Reply
|
|
83
|
+
`{ ok: false, error }` when the question is gone: the bell closes it and shows your words.
|
|
84
|
+
- `open` is where the bell's Open button lands: your app hears `{ [kind]: key }` through `useAppNav`.
|
|
85
|
+
- Answered on your own screen instead, close the bell's copy: `questions(ctx).settle(key, { answer })`
|
|
86
|
+
(or `{ cancelled: true }`). The platform does not call you back for a settle.
|
|
87
|
+
- In a Forge box there is no bell: `ask` answers `{ created: false }` and your screen still shows it.
|
|
88
|
+
|
|
64
89
|
## `callWorkspaceTool` — orchestrate other apps
|
|
65
90
|
|
|
66
91
|
```ts
|
package/llms-full.txt
CHANGED
|
@@ -880,13 +880,20 @@ snapshot baselines and the durability layers. Every shipped plugin and the scaff
|
|
|
880
880
|
|
|
881
881
|
## Events only the server emits
|
|
882
882
|
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
883
|
+
An event that records something only your server code knows — a letter sent, a sync's result, a
|
|
884
|
+
model's answer, a payment — says so with `origin: "server"`:
|
|
885
|
+
|
|
886
|
+
```ts
|
|
887
|
+
{ eventName: "mail_sent", type: EventTypes.Client, origin: "server", dataCreator, processor }
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
Your ops, routes, tasks and webhooks append it as usual (`ctx.emit`, a task's `dispatchEvent`).
|
|
891
|
+
Every door a CLIENT's event enters by refuses it — the browser's appends and offline queue, and the
|
|
892
|
+
PAT / SDK / MCP dispatch routes — so nobody with write access can plant a "sent" that was never
|
|
893
|
+
sent or a sync that never ran. Your UI can still predict it for an optimistic click (run the
|
|
894
|
+
processor locally); it just never dispatches it. `EventTypes` has no server type for this
|
|
895
|
+
(`Client`, `Workflow`, `Workspace` only — an earlier version of this page named `EventTypes.Server`,
|
|
896
|
+
which does not exist); `origin` is the switch. The processor still obeys the three rules.
|
|
890
897
|
|
|
891
898
|
## Durability you get for free
|
|
892
899
|
|
|
@@ -1001,6 +1008,33 @@ a `PluginCallError` carrying the platform's `code` (`forbidden`, `login-required
|
|
|
1001
1008
|
pass it to `useSignInWall().raise(err)` in the UI and a `login-required` becomes the sign-in wall
|
|
1002
1009
|
instead of an error. Relay any other error's message; never swallow it.
|
|
1003
1010
|
|
|
1011
|
+
## Waiting inside a network run — `mailWaitDirective`
|
|
1012
|
+
|
|
1013
|
+
Inside an agent network run (`runCtx` is the fifth argument of `toolkitCreator`; absent in chat and
|
|
1014
|
+
voice) a tool can PAUSE the run until mail arrives — minutes or days, nothing running — with the
|
|
1015
|
+
platform's own wait kernel:
|
|
1016
|
+
|
|
1017
|
+
```ts
|
|
1018
|
+
import { mailWaitDirective } from "esoul-sdk";
|
|
1019
|
+
|
|
1020
|
+
execute: async (args) => {
|
|
1021
|
+
if (!runCtx) return "Only inside an agent network run.";
|
|
1022
|
+
if (runCtx.isWaitDirectiveAlreadyCreatedThisStep()) return "One wait per turn.";
|
|
1023
|
+
eventCallback(mailWaitDirective(runCtx, {
|
|
1024
|
+
workspaceId, inboxNodeId: identifier.nodeId, inboxName: identifier.instanceName,
|
|
1025
|
+
toolName: `wait_for_email_${base}`, threadId: args.threadId,
|
|
1026
|
+
afterTimestamp, // the newest message the agent has already seen
|
|
1027
|
+
directiveId, // stable for a retried call
|
|
1028
|
+
}));
|
|
1029
|
+
runCtx.setWaitDirectiveCreatedThisStep();
|
|
1030
|
+
return "Waiting…";
|
|
1031
|
+
}
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
The run wakes on `workspace/email.message_arrived` for this inbox (the platform sends it for the
|
|
1035
|
+
Gmail app's live mail) and first checks the inbox's folded `messages` for an arrival newer than
|
|
1036
|
+
`afterTimestamp`, so a reply that landed before the wait is not missed.
|
|
1037
|
+
|
|
1004
1038
|
## Calling other apps
|
|
1005
1039
|
|
|
1006
1040
|
From the UI: `useWorkspaceTools()` (docs/05). From server code: `callWorkspaceTool` (docs/06).
|
|
@@ -1190,6 +1224,26 @@ Reload in place, without a skeleton: a screen that flashes every time the assist
|
|
|
1190
1224
|
reads as broken. Check it in the workbench: open the preview, call one of your write tools from the
|
|
1191
1225
|
board (or `esoul-forge tool …`), and watch the view change within a few seconds, without a reload.
|
|
1192
1226
|
|
|
1227
|
+
## Opened from outside: a place inside your app
|
|
1228
|
+
|
|
1229
|
+
The platform's tasks pane (and, as they adopt it, link chips and memory hits) can open a place
|
|
1230
|
+
INSIDE your app — a conversation, a campaign, a page — not just the app. It names the place with
|
|
1231
|
+
keys you choose; you hear it with `useAppNav`:
|
|
1232
|
+
|
|
1233
|
+
```tsx
|
|
1234
|
+
import { useAppNav } from "esoul-sdk/react";
|
|
1235
|
+
|
|
1236
|
+
useAppNav(nodeId, (target) => {
|
|
1237
|
+
if (target.thread) openThread(target.thread);
|
|
1238
|
+
else if (target.campaign) openCampaign(target.campaign);
|
|
1239
|
+
});
|
|
1240
|
+
```
|
|
1241
|
+
|
|
1242
|
+
`onTarget` runs with the place waiting when the app mounts (declare it after any effect that
|
|
1243
|
+
restores a remembered view, so the request wins) and with each one asked for while the app is on
|
|
1244
|
+
screen. An unknown key does nothing. Name the keys in your task descriptions so the platform can
|
|
1245
|
+
point at them.
|
|
1246
|
+
|
|
1193
1247
|
## Cross-app from the UI
|
|
1194
1248
|
|
|
1195
1249
|
```ts
|
|
@@ -1306,6 +1360,31 @@ One app, folded to head: `{ nodeId, workspaceId, applicationType, foldedSeq, sta
|
|
|
1306
1360
|
when absent. Use it for your own instance and, with care, for other apps in the same workspace.
|
|
1307
1361
|
Never a raw database read — the import wall refuses `prisma` and the state column lags the log.
|
|
1308
1362
|
|
|
1363
|
+
## Asking the person — `questions(ctx)`
|
|
1364
|
+
|
|
1365
|
+
A question your app needs answered (an agent waiting on a decision) goes to the platform's
|
|
1366
|
+
questions bell, which the person sees on every workspace — not only when your app is open:
|
|
1367
|
+
|
|
1368
|
+
```ts
|
|
1369
|
+
import { questions } from "esoul-sdk/server";
|
|
1370
|
+
|
|
1371
|
+
await questions(ctx).ask({
|
|
1372
|
+
key: `thread:${threadId}:${questionId}`, // one question per key: a replayed ask is the same one
|
|
1373
|
+
question: "Accept 12 % off if they order 500?",
|
|
1374
|
+
options: ["Yes", "No"], // 1–4 → buttons; without them the person types
|
|
1375
|
+
open: { kind: "thread", key: threadId, label: "Open email thread" },
|
|
1376
|
+
answer: { op: "answer_question", args: { threadId, questionId, via: "bell" } },
|
|
1377
|
+
});
|
|
1378
|
+
```
|
|
1379
|
+
|
|
1380
|
+
- Answered in the bell, the platform calls **your own op** (`answer.op`, one of your declared ops)
|
|
1381
|
+
with `{ ...args, answer }`, as the person who answered — their access, your op's rules. Reply
|
|
1382
|
+
`{ ok: false, error }` when the question is gone: the bell closes it and shows your words.
|
|
1383
|
+
- `open` is where the bell's Open button lands: your app hears `{ [kind]: key }` through `useAppNav`.
|
|
1384
|
+
- Answered on your own screen instead, close the bell's copy: `questions(ctx).settle(key, { answer })`
|
|
1385
|
+
(or `{ cancelled: true }`). The platform does not call you back for a settle.
|
|
1386
|
+
- In a Forge box there is no bell: `ask` answers `{ created: false }` and your screen still shows it.
|
|
1387
|
+
|
|
1309
1388
|
## `callWorkspaceTool` — orchestrate other apps
|
|
1310
1389
|
|
|
1311
1390
|
```ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "esoul-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Build a full product on ExternalSoul: your own tables with per-person rules, a viewer on every seam, app roles, access levels, realtime with audiences, durable tasks, and bindings to other apps.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|