@sanoma-ai/workflows 0.11.15 → 0.11.17
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/README.md +14 -3
- package/dist/app-steps.d.ts +17 -0
- package/dist/app-steps.js +43 -0
- package/dist/app-steps.js.map +1 -0
- package/dist/app-workflows.d.ts +170 -0
- package/dist/app-workflows.js +107 -0
- package/dist/app-workflows.js.map +1 -0
- package/dist/apply-steps.js +3 -9
- package/dist/apply-steps.js.map +1 -1
- package/dist/approvals.d.ts +1 -1
- package/dist/approvals.js +3 -0
- package/dist/approvals.js.map +1 -1
- package/dist/call.d.ts +2 -1
- package/dist/call.js +2 -1
- package/dist/call.js.map +1 -1
- package/dist/change-steps.js +11 -17
- package/dist/change-steps.js.map +1 -1
- package/dist/chat-steps.d.ts +5 -0
- package/dist/chat-steps.js +107 -0
- package/dist/chat-steps.js.map +1 -0
- package/dist/chat-workflow.d.ts +43 -0
- package/dist/chat-workflow.js +47 -0
- package/dist/chat-workflow.js.map +1 -0
- package/dist/chats.d.ts +23 -4
- package/dist/chats.js +54 -7
- package/dist/chats.js.map +1 -1
- package/dist/client.d.ts +42 -31
- package/dist/client.js +118 -105
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +20 -0
- package/dist/config.js +55 -4
- package/dist/config.js.map +1 -1
- package/dist/db/company.d.ts +259 -2
- package/dist/db/company.js +32 -1
- package/dist/db/company.js.map +1 -1
- package/dist/db.d.ts +15 -0
- package/dist/db.js +42 -2
- package/dist/db.js.map +1 -1
- package/dist/description.d.ts +6 -3
- package/dist/description.js +4 -3
- package/dist/description.js.map +1 -1
- package/dist/follow-steps.d.ts +8 -0
- package/dist/follow-steps.js +113 -0
- package/dist/follow-steps.js.map +1 -0
- package/dist/follow-workflow.d.ts +56 -0
- package/dist/follow-workflow.js +50 -0
- package/dist/follow-workflow.js.map +1 -0
- package/dist/index.d.ts +10 -5
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/dist/local-sandbox.d.ts +10 -0
- package/dist/local-sandbox.js +130 -0
- package/dist/local-sandbox.js.map +1 -0
- package/dist/op.d.ts +9 -2
- package/dist/op.js.map +1 -1
- package/dist/paths.d.ts +9 -0
- package/dist/paths.js +20 -4
- package/dist/paths.js.map +1 -1
- package/dist/resource.d.ts +7 -1
- package/dist/resource.js +5 -1
- package/dist/resource.js.map +1 -1
- package/dist/run.d.ts +39 -0
- package/dist/run.js +15 -0
- package/dist/run.js.map +1 -1
- package/dist/sandbox-contract.d.ts +100 -0
- package/dist/sandbox-contract.js +26 -0
- package/dist/sandbox-contract.js.map +1 -0
- package/dist/sandbox.d.ts +10 -0
- package/dist/sandbox.js +42 -4
- package/dist/sandbox.js.map +1 -1
- package/dist/scenario.d.ts +19 -0
- package/dist/scenario.js.map +1 -1
- package/dist/schedules.d.ts +11 -3
- package/dist/schedules.js +15 -3
- package/dist/schedules.js.map +1 -1
- package/dist/seal.d.ts +7 -0
- package/dist/seal.js +14 -2
- package/dist/seal.js.map +1 -1
- package/dist/shared.d.ts +34 -2
- package/dist/shared.js +39 -2
- package/dist/shared.js.map +1 -1
- package/dist/worker.d.ts +8 -0
- package/dist/worker.js +116 -10
- package/dist/worker.js.map +1 -1
- package/drizzle/company/0002_runs_tell_the_app.sql +27 -0
- package/drizzle/company/meta/0002_snapshot.json +819 -0
- package/drizzle/company/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/src/app-steps.ts +67 -0
- package/src/app-workflows.ts +251 -0
- package/src/apply-steps.ts +3 -9
- package/src/approvals.ts +3 -1
- package/src/call.ts +2 -1
- package/src/change-steps.ts +10 -17
- package/src/chat-steps.ts +117 -0
- package/src/chat-workflow.ts +69 -0
- package/src/chats.ts +80 -14
- package/src/client.ts +154 -109
- package/src/config.ts +66 -3
- package/src/db/company.ts +49 -2
- package/src/db.ts +51 -3
- package/src/description.ts +4 -3
- package/src/follow-steps.ts +129 -0
- package/src/follow-workflow.ts +88 -0
- package/src/index.ts +32 -3
- package/src/local-sandbox.ts +132 -0
- package/src/op.ts +9 -2
- package/src/paths.ts +22 -4
- package/src/resource.ts +16 -2
- package/src/run.ts +41 -0
- package/src/sandbox-contract.ts +114 -0
- package/src/sandbox.ts +41 -4
- package/src/scenario.ts +17 -0
- package/src/schedules.ts +19 -4
- package/src/seal.ts +16 -2
- package/src/shared.ts +47 -2
- package/src/worker.ts +149 -10
package/dist/chats.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chats.js","sourceRoot":"","sources":["../src/chats.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"chats.js","sourceRoot":"","sources":["../src/chats.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA0D1C,MAAM,MAAM,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAA6B,EAAQ,EAAE,CAAC,CAAC;IACtG,EAAE;IACF,MAAM;IACN,MAAM;IACN,KAAK;IACL,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;IACxC,SAAS,EAAE,SAAS,CAAC,OAAO,EAAE;CAC/B,CAAC,CAAC;AAEH,8FAA8F;AAC9F,MAAM,UAAU,SAAS,CAAC,EAAqB;IAC7C,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,CACnB,MAAM,EAAE,EAAE,CACX;iBACE,MAAM,CAAC,KAAK,CAAC;iBACb,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;iBACrC,mBAAmB,EAAE;iBACrB,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,MAAM;gBAAE,MAAM,IAAI,WAAW,CAAC,eAAe,EAAE,QAAQ,EAAE,0CAA0C,CAAC,CAAC;QACnH,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO;YACtB,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAC5E,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO;YAChC,IAAI,CAAC,QAAQ,CAAC,MAAM;gBAAE,OAAO;YAC7B,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAAE,MAAM,IAAI,WAAW,CAAC,eAAe,EAAE,4BAA4B,CAAC,CAAC;YACtG,yFAAyF;YACzF,MAAM,IAAI,GAAG,GAAG,CAAA,wBAAwB,YAAY,CAAC,GAAG,cAAc,YAAY,UAAU,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC;YAC3H,MAAM,CACJ,MAAM,EAAE,EAAE,CACX;iBACE,MAAM,CAAC,YAAY,CAAC;iBACpB,MAAM,CACL,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAQ,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,CAC9G;iBACA,kBAAkB,CAAC;gBAClB,MAAM,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC;gBAC9C,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,CAAA,kBAAkB,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,GAAG,EAAE,GAAG,CAAA,cAAc,EAAE,CAAC,EAAE;aAC1F,CAAC,CAAC;QACP,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE;YACX,MAAM,IAAI,GAAG,MAAM,CACjB,MAAM,EAAE,EAAE,CACX;iBACE,MAAM,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC;iBACzC,IAAI,CAAC,YAAY,CAAC;iBAClB,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;iBAClC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;YACxD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACxC,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO;YACnB,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAClB,MAAM,EAAE,EAAE,CACX;iBACE,MAAM,CAAC,EAAE,EAAE,EAAE,YAAY,CAAC,EAAE,EAAE,CAAC;iBAC/B,IAAI,CAAC,YAAY,CAAC;iBAClB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;YACzE,OAAO,GAAG,KAAK,SAAS,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,EAAE;YACV,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAC9E,OAAO,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI;YAClB,MAAM,QAAQ,GAAG,MAAM,EAAE,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,MAAM,QAAQ;iBACzB,MAAM,CAAC,KAAK,CAAC;iBACb,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC;iBACb,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAA,GAAG,KAAK,CAAC,IAAI,qBAAqB,IAAI,EAAE,CAAC,CAAC;iBACzE,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/B,MAAM,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YACpG,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1B,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM;YAC3B,IAAI,MAAM,CAAC,MAAM;gBAAE,MAAM,YAAY,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACtE,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI;YAChB,MAAM,YAAY,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QACnD,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK;YACtB,MAAM,IAAI,GAAG,MAAM,CACjB,MAAM,EAAE,EAAE,CACX;iBACE,MAAM,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC;iBACxD,IAAI,CAAC,UAAU,CAAC;iBAChB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;iBACjE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;YAChC,OAAO;gBACL,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;gBACtE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,KAAK;gBAC/B,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI;aACnC,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,MAAM;YACf,MAAM,IAAI,GAAG,MAAM,CACjB,MAAM,EAAE,EAAE,CACX;iBACE,MAAM,EAAE;iBACR,IAAI,CAAC,KAAK,CAAC;iBACX,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;iBAC/B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;iBAC7C,KAAK,CAAC,EAAE,CAAC,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;KACF,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,KAAK,UAAU,YAAY,CAAC,EAAM,EAAE,EAAU,EAAE,IAAY,EAAE,MAA0C;IACtG,gEAAgE;IAChE,MAAM,IAAI,GAAG,GAAG,CAAA,wBAAwB,UAAU,CAAC,GAAG,cAAc,UAAU,UAAU,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC;IACtH,MAAM,EAAE;SACL,MAAM,CAAC,UAAU,CAAC;SAClB,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAQ,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AAClH,CAAC"}
|
package/dist/client.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { ApprovalMessage } from "./approvals.ts";
|
|
|
6
6
|
import { type Chats } from "./chats.ts";
|
|
7
7
|
import { type Tokens } from "./tokens.ts";
|
|
8
8
|
import { type SanomaConfig } from "./config.ts";
|
|
9
|
+
import { type AppBehind } from "./db.ts";
|
|
9
10
|
import { type CredentialStatus } from "./env.ts";
|
|
10
11
|
import { type ApprovalState, Principal, type WorkflowDefinition } from "./define.ts";
|
|
11
12
|
import { type ApplyInput, type ApplyReport } from "./apply.ts";
|
|
@@ -15,7 +16,9 @@ import { type LedgerRecord } from "./ledger.ts";
|
|
|
15
16
|
import type { SignInMethod } from "./op.ts";
|
|
16
17
|
import { type SecretLocation } from "./secret-store.ts";
|
|
17
18
|
import { type RunStatus } from "./shared.ts";
|
|
18
|
-
import
|
|
19
|
+
import type { ChatTurnInput } from "./chat-workflow.ts";
|
|
20
|
+
import type { RunChecks } from "./scenario.ts";
|
|
21
|
+
import type { RemoteEvent } from "./source.ts";
|
|
19
22
|
/** A run's status from DBOS's, and whether it has an approval pending. */
|
|
20
23
|
export declare function runStatus(dbosStatus: string, approvals: readonly ApprovalState[]): RunStatus;
|
|
21
24
|
/** The DBOS statuses the run statuses come from; `running` and `waiting` both come from PENDING. */
|
|
@@ -122,11 +125,6 @@ export interface ClientOptions {
|
|
|
122
125
|
* runs a worker that stops when idle starts it again with it (`Supervisor.resume`). Must not throw.
|
|
123
126
|
*/
|
|
124
127
|
onWrite?: () => void;
|
|
125
|
-
/**
|
|
126
|
-
* The company's repository, as the worker is given it: what `remoteEvent` acts for (its
|
|
127
|
-
* `origin`) and fetches a draft's new commits into. Without one, `remoteEvent` does nothing.
|
|
128
|
-
*/
|
|
129
|
-
source?: Source;
|
|
130
128
|
/**
|
|
131
129
|
* The version each run it starts is queued for, so only a worker of that code runs it: the app
|
|
132
130
|
* bundle's (its snapshot's), which is live beside a worker of another version while a deploy
|
|
@@ -169,7 +167,9 @@ export declare class SanomaClient {
|
|
|
169
167
|
* The policy's answer to starting a run of `workflow` as `startedBy` (`decideStart`), for a
|
|
170
168
|
* workflow of the config's own: a deny throws `policy_denied`; a hold is what the run waits on
|
|
171
169
|
* before its body. A run `runId` names already is returned as it is, whatever the policy says now, but to a visitor.
|
|
172
|
-
* A visitor (`isVisitor
|
|
170
|
+
* A visitor (`isVisitor`, an api token's principal too) starts no built-in but `call`, whose calls
|
|
171
|
+
* the policy decides as direct ones: the app's own actions on the repository (`app-workflows.ts`)
|
|
172
|
+
* are staff's, as their server functions were, which no site's host answered.
|
|
173
173
|
*/
|
|
174
174
|
private startHold;
|
|
175
175
|
/**
|
|
@@ -330,6 +330,11 @@ export declare class SanomaClient {
|
|
|
330
330
|
* or the others, else all; at most `limit` (20).
|
|
331
331
|
*/
|
|
332
332
|
changes({ open, limit }?: ChangesFilter): Promise<ChangeView[]>;
|
|
333
|
+
/**
|
|
334
|
+
* Whether a change is merging or deploying `main` now (`ChangeState.phase`, as its run last
|
|
335
|
+
* published it), which follows `main` and applies the hosts itself.
|
|
336
|
+
*/
|
|
337
|
+
changeDeploying(): Promise<boolean>;
|
|
333
338
|
/** The change of the draft `id`: its latest run's (`openChange`), or undefined when it has none. */
|
|
334
339
|
change(id: string): Promise<ChangeView | undefined>;
|
|
335
340
|
/**
|
|
@@ -347,34 +352,40 @@ export declare class SanomaClient {
|
|
|
347
352
|
key?: string;
|
|
348
353
|
}): Promise<void>;
|
|
349
354
|
/**
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
355
|
+
* Starts the built-in follow workflow on what a host's webhook says happened (`RemoteEvent`,
|
|
356
|
+
* from a remote half's `webhook`, verified), as the runtime's agent `host-check`: the worker,
|
|
357
|
+
* which has the checkout, follows it there (`follow-workflow.ts`). Its run id is
|
|
358
|
+
* `follow:<sha256 of the event>`, so a delivery told again is the one run. Its id.
|
|
359
|
+
*/
|
|
360
|
+
follow(event: RemoteEvent): Promise<string>;
|
|
361
|
+
/**
|
|
362
|
+
* Starts a turn of the chat `input.chat` on the person's new message `input.message`, already in
|
|
363
|
+
* its transcript (`chats.upsert`), as `startedBy`, the chat's person: the built-in chat workflow,
|
|
364
|
+
* as the run `chat:<chat>:<message>` (`chatRunId`), after the chat's turn before it, which it
|
|
365
|
+
* waits for; that turn, when it has not ended, is told to stop. The worker runs the turn and
|
|
366
|
+
* writes its reply (`chats.chunks`, then the transcript). Its run id.
|
|
367
|
+
*/
|
|
368
|
+
startTurn(input: Omit<ChatTurnInput, "after">, options: StartOptions): Promise<string>;
|
|
369
|
+
/** The chat's latest turn (`startTurn`), or undefined when it has had none. */
|
|
370
|
+
turn(chat: string): Promise<RunSummary | undefined>;
|
|
371
|
+
/**
|
|
372
|
+
* Hands `code`, which the person pasted on their own agent's sign-in card, to the sign-in waiting
|
|
373
|
+
* in the turn under way of their chat `chat`, sealed (`sealChatCode`), so the run's messages never
|
|
374
|
+
* show it. `run_not_found` when the chat has no turn under way of `by`'s.
|
|
375
|
+
*/
|
|
376
|
+
turnCode(chat: string, code: string, options: {
|
|
365
377
|
by: Principal | string;
|
|
366
378
|
}): Promise<void>;
|
|
367
|
-
/** After a push of `head` to `main` (`remoteEvent`): the checkout follows it, then apply on the declared hosts. */
|
|
368
|
-
private deployPush;
|
|
369
|
-
/** Where each open change is (`ChangeState.phase`), read from what its run last published. */
|
|
370
|
-
private openChangePhases;
|
|
371
379
|
/**
|
|
372
|
-
*
|
|
373
|
-
*
|
|
380
|
+
* How far the app `folder` (taken from a source) is behind its source, or why that cannot be
|
|
381
|
+
* told, as the worker last checked (at its start and after the checkout follows `main`);
|
|
382
|
+
* undefined when it has not told it.
|
|
374
383
|
*/
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
|
|
384
|
+
appBehind(folder: string): Promise<AppBehind | undefined>;
|
|
385
|
+
/** A sandbox run's checks against its scenario as the worker last ran them (when the run last waited or ended); undefined for none yet. */
|
|
386
|
+
runChecks(runId: string): Promise<RunChecks | undefined>;
|
|
387
|
+
/** The latest `limit` turns of the chat `chat`, newest first: its runs `chat:<chat>:<message>` (`chatRunPrefix`). */
|
|
388
|
+
private turns;
|
|
378
389
|
/** The runs of the draft `id`'s change, newest first: `change:<id>` and `change:<id>~<n>`. */
|
|
379
390
|
private changeRuns;
|
|
380
391
|
/** A change run's row as the app shows it: its summary, its last `ChangeState` and, once finished, its report. */
|
package/dist/client.js
CHANGED
|
@@ -13,23 +13,21 @@ import { tokenStore } from "./tokens.js";
|
|
|
13
13
|
import { collectionsDriver } from "./collection.js";
|
|
14
14
|
import { resolveConfig } from "./config.js";
|
|
15
15
|
import { configuredSecrets } from "./credentials.js";
|
|
16
|
-
import { dbosClient, lazyDb, spendInviteRequest } from "./db.js";
|
|
16
|
+
import { dbosClient, lazyDb, readAppBehind, readRunChecks, spendInviteRequest, } from "./db.js";
|
|
17
17
|
import { credentialsOf } from "./env.js";
|
|
18
18
|
import { Principal } from "./define.js";
|
|
19
19
|
import { APPLY_WORKFLOW } from "./apply.js";
|
|
20
|
-
import { ADMIN,
|
|
20
|
+
import { ADMIN, ChangeEventSchema, ChangeInput, initialChangeState, } from "./change.js";
|
|
21
21
|
import { DRIFT_WORKFLOW } from "./drift.js";
|
|
22
22
|
import { isDirect } from "./direct.js";
|
|
23
|
-
import { ApprovalPendingError, errorCode, errorInfo, NotAdmittedError, parseOrThrow, PolicyDeniedError, SanomaError,
|
|
23
|
+
import { ApprovalPendingError, errorCode, errorInfo, NotAdmittedError, parseOrThrow, PolicyDeniedError, SanomaError, } from "./errors.js";
|
|
24
24
|
import { insertRecord, lastInvite, lastSignIns, loginRecord, ownedLedger, } from "./ledger.js";
|
|
25
|
-
import { warn } from "./log.js";
|
|
26
25
|
import { allowAll } from "./policy.js";
|
|
27
26
|
import { admit, readPeople } from "./resources.js";
|
|
28
27
|
import { SecretStoreError } from "./secret-store.js";
|
|
29
|
-
import { BUILT_IN_WORKFLOWS, CALL_WORKFLOW, CHANGE_EVENT, CHANGE_MERGE, CHANGE_TOPIC, CHANGE_WORKFLOW, changeIdOf, DATA_VENDOR, ENDED_STATUSES, errorMessage, HOST_CHECK_AGENT, isEnded, isToken, isVisitor, refusalOf, SCHEDULE_AGENT, WORKFLOW_ACTION, } from "./shared.js";
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
const sameRepo = (a, b) => a.owner.toLowerCase() === b.owner.toLowerCase() && a.name.toLowerCase() === b.name.toLowerCase();
|
|
28
|
+
import { BUILT_IN_WORKFLOWS, CALL_WORKFLOW, CHANGE_EVENT, CHANGE_MERGE, CHANGE_TOPIC, CHANGE_WORKFLOW, CHAT_TOPIC, CHAT_WORKFLOW, changeIdOf, chatRunId, chatRunPrefix, DATA_VENDOR, DRAFT_ID, ENDED_STATUSES, errorMessage, FOLLOW_WORKFLOW, HOST_CHECK_AGENT, isEnded, isToken, isVisitor, refusalOf, SCHEDULE_AGENT, WORKFLOW_ACTION, } from "./shared.js";
|
|
29
|
+
import { RemoteEventSchema } from "./follow-workflow.js";
|
|
30
|
+
import { sealChatCode } from "./seal.js";
|
|
33
31
|
/** A principal, or its id alone. */
|
|
34
32
|
const PrincipalOrId = z.union([
|
|
35
33
|
z
|
|
@@ -142,10 +140,12 @@ export class SanomaClient {
|
|
|
142
140
|
const parsed = parseOrThrow(workflow.input, input, `The input does not match ${workflow.name}'s schema`);
|
|
143
141
|
const { runId } = options;
|
|
144
142
|
const sandbox = parseOrThrow(z.string().min(1).optional(), options.sandbox, "`sandbox` must be the name of a scenario in the config's `scenarios/`");
|
|
145
|
-
if (workflow.name === CHANGE_WORKFLOW && !isChangeRunOf(parsed.id, runId)) {
|
|
146
|
-
throw new SanomaError("invalid_input", "A change is started with openChange, which names its run", { runId });
|
|
147
|
-
}
|
|
148
143
|
const hold = await this.startHold(workflow.name, parsed, startedBy, runId);
|
|
144
|
+
const own = OWN_STARTS[workflow.name];
|
|
145
|
+
if (own && !(await own.admits(parsed, startedBy, runId, this))) {
|
|
146
|
+
const refused = `A run of ${workflow.name} is started with ${own.by}, which names its run`;
|
|
147
|
+
throw new SanomaError("invalid_input", refused, { runId });
|
|
148
|
+
}
|
|
149
149
|
const args = { input, startedBy, ...(sandbox === undefined ? {} : { sandbox }), ...(hold && { hold }) };
|
|
150
150
|
// Kept on the run's status row too, so a listing tells sandbox runs apart without its input,
|
|
151
151
|
// and says whom an agent's run is for (DBOS keeps the principal's id and groups itself); a
|
|
@@ -183,7 +183,9 @@ export class SanomaClient {
|
|
|
183
183
|
* The policy's answer to starting a run of `workflow` as `startedBy` (`decideStart`), for a
|
|
184
184
|
* workflow of the config's own: a deny throws `policy_denied`; a hold is what the run waits on
|
|
185
185
|
* before its body. A run `runId` names already is returned as it is, whatever the policy says now, but to a visitor.
|
|
186
|
-
* A visitor (`isVisitor
|
|
186
|
+
* A visitor (`isVisitor`, an api token's principal too) starts no built-in but `call`, whose calls
|
|
187
|
+
* the policy decides as direct ones: the app's own actions on the repository (`app-workflows.ts`)
|
|
188
|
+
* are staff's, as their server functions were, which no site's host answered.
|
|
187
189
|
*/
|
|
188
190
|
async startHold(workflow, input, startedBy, runId) {
|
|
189
191
|
const { policy } = this.config;
|
|
@@ -660,6 +662,21 @@ export class SanomaClient {
|
|
|
660
662
|
const rows = await this.dbos.listWorkflows({ workflowIDs: ids, sortDesc: true, loadInput: true, loadOutput: true });
|
|
661
663
|
return Promise.all(rows.map((row) => this.changeView(row)));
|
|
662
664
|
}
|
|
665
|
+
/**
|
|
666
|
+
* Whether a change is merging or deploying `main` now (`ChangeState.phase`, as its run last
|
|
667
|
+
* published it), which follows `main` and applies the hosts itself.
|
|
668
|
+
*/
|
|
669
|
+
async changeDeploying() {
|
|
670
|
+
const rows = await this.dbos.listWorkflows({
|
|
671
|
+
workflowName: CHANGE_WORKFLOW,
|
|
672
|
+
applicationName: this.config.appName,
|
|
673
|
+
status: dbosStatusesOf("queued", "running"),
|
|
674
|
+
loadInput: false,
|
|
675
|
+
loadOutput: false,
|
|
676
|
+
});
|
|
677
|
+
const phases = await Promise.all(rows.map(async (row) => (await this.dbos.getEvent(row.workflowID, CHANGE_EVENT, 0))?.phase));
|
|
678
|
+
return phases.some((phase) => phase === "merging" || phase === "deploying");
|
|
679
|
+
}
|
|
663
680
|
/** The change of the draft `id`: its latest run's (`openChange`), or undefined when it has none. */
|
|
664
681
|
async change(id) {
|
|
665
682
|
const [row] = await this.changeRuns(id, { load: true });
|
|
@@ -708,108 +725,78 @@ export class SanomaClient {
|
|
|
708
725
|
}
|
|
709
726
|
}
|
|
710
727
|
/**
|
|
711
|
-
*
|
|
712
|
-
*
|
|
713
|
-
*
|
|
714
|
-
*
|
|
715
|
-
* - `pushed` to `main`: the checkout follows `main`, then apply on the declared hosts
|
|
716
|
-
* (`ResolvedConfig.hosts`) as `host-check`, as the run `deploy:<head>`, once per head; nothing
|
|
717
|
-
* with no host, nor while a change is merging or deploying, which does both itself.
|
|
718
|
-
* - `pushed` to a draft's branch (`draftOf`) with its change open: the host's commits fetched into
|
|
719
|
-
* the draft (`Source.follow` on its branch), then the change told `commits`, as `by`; nothing
|
|
720
|
-
* when the change or the draft is at that head already (the run's own push), or when the draft
|
|
721
|
-
* cannot fast-forward to it (warned).
|
|
722
|
-
* - `closed` for the open change's pull request: the change told `merged` (with its merge commit)
|
|
723
|
-
* or `closed`, as `by`. The run checks either on the host before it believes it.
|
|
728
|
+
* Starts the built-in follow workflow on what a host's webhook says happened (`RemoteEvent`,
|
|
729
|
+
* from a remote half's `webhook`, verified), as the runtime's agent `host-check`: the worker,
|
|
730
|
+
* which has the checkout, follows it there (`follow-workflow.ts`). Its run id is
|
|
731
|
+
* `follow:<sha256 of the event>`, so a delivery told again is the one run. Its id.
|
|
724
732
|
*/
|
|
725
|
-
async
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
if (!main && id === undefined)
|
|
729
|
-
return;
|
|
730
|
-
const repository = await this.repository();
|
|
731
|
-
if (!repository || !sameRepo(repository.repo, event.repo))
|
|
732
|
-
return;
|
|
733
|
-
if (main)
|
|
734
|
-
return this.deployPush(repository, event.head);
|
|
735
|
-
const change = await this.change(id);
|
|
736
|
-
if (!change || isEnded(change.status))
|
|
737
|
-
return;
|
|
738
|
-
let told;
|
|
739
|
-
let key;
|
|
740
|
-
if (event.kind === "closed") {
|
|
741
|
-
// A pull request of an earlier change of the draft is not this one's.
|
|
742
|
-
if (event.number !== change.state.pullRequest?.number)
|
|
743
|
-
return;
|
|
744
|
-
told = event.merged && event.sha !== undefined ? { kind: "merged", sha: event.sha } : { kind: "closed" };
|
|
745
|
-
key = `${event.number}:${event.sha ?? "closed"}`;
|
|
746
|
-
}
|
|
747
|
-
else {
|
|
748
|
-
if (change.state.head === event.head || !(await this.fetched(repository, event.branch, event.head)))
|
|
749
|
-
return;
|
|
750
|
-
told = { kind: "commits" };
|
|
751
|
-
key = event.head;
|
|
752
|
-
}
|
|
753
|
-
await this.changeEvent(id, told, { by: options.by, key: `${event.kind}:${event.branch}:${key}` }).catch((err) => {
|
|
754
|
-
// Ended, or gone, since it was read: nothing to tell.
|
|
755
|
-
if (!["run_ended", "run_not_found"].includes(errorCode(err) ?? ""))
|
|
756
|
-
throw err;
|
|
757
|
-
});
|
|
733
|
+
async follow(event) {
|
|
734
|
+
const parsed = parseOrThrow(RemoteEventSchema, event, "Not an event of a host's webhook");
|
|
735
|
+
return this.start(FOLLOW_WORKFLOW, parsed, { startedBy: HOST_CHECK_AGENT, runId: followRunId(parsed) });
|
|
758
736
|
}
|
|
759
|
-
/**
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
737
|
+
/**
|
|
738
|
+
* Starts a turn of the chat `input.chat` on the person's new message `input.message`, already in
|
|
739
|
+
* its transcript (`chats.upsert`), as `startedBy`, the chat's person: the built-in chat workflow,
|
|
740
|
+
* as the run `chat:<chat>:<message>` (`chatRunId`), after the chat's turn before it, which it
|
|
741
|
+
* waits for; that turn, when it has not ended, is told to stop. The worker runs the turn and
|
|
742
|
+
* writes its reply (`chats.chunks`, then the transcript). Its run id.
|
|
743
|
+
*/
|
|
744
|
+
async startTurn(input, options) {
|
|
745
|
+
const runId = chatRunId(input.chat, input.message);
|
|
746
|
+
// The latest other than this one, which a start told again finds first.
|
|
747
|
+
const before = (await this.turns(input.chat, 2)).find((row) => row.workflowID !== runId);
|
|
748
|
+
await this.start(CHAT_WORKFLOW, { ...input, ...(before && { after: before.workflowID }) }, {
|
|
749
|
+
...options,
|
|
750
|
+
runId,
|
|
751
|
+
});
|
|
752
|
+
// Once the new turn stands, which refused anyone but the chat's person.
|
|
753
|
+
if (before && !isEnded(runStatus(before.status, []))) {
|
|
754
|
+
await this.dbos.send(before.workflowID, { kind: "stop" }, CHAT_TOPIC);
|
|
771
755
|
}
|
|
772
|
-
|
|
773
|
-
if (hosts.length)
|
|
774
|
-
await this.apply({ only: hosts }, { startedBy: HOST_CHECK_AGENT, runId });
|
|
756
|
+
return runId;
|
|
775
757
|
}
|
|
776
|
-
/**
|
|
777
|
-
async
|
|
778
|
-
const
|
|
779
|
-
|
|
780
|
-
applicationName: this.config.appName,
|
|
781
|
-
status: dbosStatusesOf("queued", "running"),
|
|
782
|
-
loadInput: false,
|
|
783
|
-
loadOutput: false,
|
|
784
|
-
});
|
|
785
|
-
return Promise.all(rows.map(async (r) => (await this.dbos.getEvent(r.workflowID, CHANGE_EVENT, 0))?.phase));
|
|
758
|
+
/** The chat's latest turn (`startTurn`), or undefined when it has had none. */
|
|
759
|
+
async turn(chat) {
|
|
760
|
+
const [row] = await this.turns(chat, 1);
|
|
761
|
+
return row && this.summarize(row);
|
|
786
762
|
}
|
|
787
763
|
/**
|
|
788
|
-
*
|
|
789
|
-
*
|
|
764
|
+
* Hands `code`, which the person pasted on their own agent's sign-in card, to the sign-in waiting
|
|
765
|
+
* in the turn under way of their chat `chat`, sealed (`sealChatCode`), so the run's messages never
|
|
766
|
+
* show it. `run_not_found` when the chat has no turn under way of `by`'s.
|
|
790
767
|
*/
|
|
791
|
-
async
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
? await source.follow({ url, token: await host.token(), ref: branch })
|
|
797
|
-
: { skipped: "this repository cannot follow its remote" };
|
|
798
|
-
if ("skipped" in moved) {
|
|
799
|
-
warn(`${branch} did not take the host's commits: ${moved.skipped}`);
|
|
800
|
-
return false;
|
|
768
|
+
async turnCode(chat, code, options) {
|
|
769
|
+
const by = await this.admitted(parseOrThrow(PrincipalOrId, options?.by, '`by` must be a principal, such as "alice" or { id: "alice" }'));
|
|
770
|
+
const [row] = await this.turns(chat, 1);
|
|
771
|
+
if (!row || isEnded(runStatus(row.status, [])) || row.authenticatedUser !== by.id) {
|
|
772
|
+
throw new SanomaError("run_not_found", `No turn of chat ${chat} is under way`, { chat });
|
|
801
773
|
}
|
|
802
|
-
|
|
774
|
+
const told = { kind: "code", sealed: sealChatCode(row.workflowID, code) };
|
|
775
|
+
await this.dbos.send(row.workflowID, told, CHAT_TOPIC);
|
|
803
776
|
}
|
|
804
|
-
/**
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
777
|
+
/**
|
|
778
|
+
* How far the app `folder` (taken from a source) is behind its source, or why that cannot be
|
|
779
|
+
* told, as the worker last checked (at its start and after the checkout follows `main`);
|
|
780
|
+
* undefined when it has not told it.
|
|
781
|
+
*/
|
|
782
|
+
async appBehind(folder) {
|
|
783
|
+
return readAppBehind(await this.database.db(), folder);
|
|
784
|
+
}
|
|
785
|
+
/** A sandbox run's checks against its scenario as the worker last ran them (when the run last waited or ended); undefined for none yet. */
|
|
786
|
+
async runChecks(runId) {
|
|
787
|
+
return readRunChecks(await this.database.db(), runId);
|
|
788
|
+
}
|
|
789
|
+
/** The latest `limit` turns of the chat `chat`, newest first: its runs `chat:<chat>:<message>` (`chatRunPrefix`). */
|
|
790
|
+
async turns(chat, limit) {
|
|
791
|
+
return this.dbos.listWorkflows({
|
|
792
|
+
// DBOS matches the prefix with LIKE as given, where a chat id's `_` is any character: escaped.
|
|
793
|
+
workflow_id_prefix: chatRunPrefix(chat).replaceAll(/[\\%_]/g, "\\$&"),
|
|
794
|
+
workflowName: CHAT_WORKFLOW,
|
|
795
|
+
applicationName: this.config.appName,
|
|
796
|
+
sortDesc: true,
|
|
797
|
+
limit,
|
|
798
|
+
loadInput: false,
|
|
799
|
+
loadOutput: false,
|
|
813
800
|
});
|
|
814
801
|
}
|
|
815
802
|
/** The runs of the draft `id`'s change, newest first: `change:<id>` and `change:<id>~<n>`. */
|
|
@@ -1273,6 +1260,32 @@ const alreadyDecided = (runId, a) => new SanomaError("already_decided", a.status
|
|
|
1273
1260
|
...(a.decidedBy === undefined ? {} : { decidedBy: a.decidedBy }),
|
|
1274
1261
|
...(a.withdrawnReason === undefined ? {} : { withdrawnReason: a.withdrawnReason }),
|
|
1275
1262
|
});
|
|
1263
|
+
/**
|
|
1264
|
+
* The built-ins only one of the client's methods starts, by name: that method (`by`), and whether
|
|
1265
|
+
* a start is its own (`admits`), which `start` asks once the policy has (a visitor is denied
|
|
1266
|
+
* first), refusing any other: a change under the id `openChange` names; a follow as `host-check`
|
|
1267
|
+
* under its event's id; a chat turn under its chat's and message's id, after a turn of the same
|
|
1268
|
+
* chat, as the chat's person.
|
|
1269
|
+
*/
|
|
1270
|
+
const OWN_STARTS = {
|
|
1271
|
+
[CHANGE_WORKFLOW]: { by: "openChange", admits: (input, _by, runId) => isChangeRunOf(input.id, runId) },
|
|
1272
|
+
[FOLLOW_WORKFLOW]: {
|
|
1273
|
+
by: "follow",
|
|
1274
|
+
admits: (event, by, runId) => runId === followRunId(event) && by.id === HOST_CHECK_AGENT,
|
|
1275
|
+
},
|
|
1276
|
+
[CHAT_WORKFLOW]: {
|
|
1277
|
+
by: "startTurn",
|
|
1278
|
+
admits: async ({ chat, message, after }, by, runId, client) => runId === chatRunId(chat, message) &&
|
|
1279
|
+
(after === undefined ||
|
|
1280
|
+
(after.startsWith(chatRunPrefix(chat)) && DRAFT_ID.test(after.slice(chatRunPrefix(chat).length)))) &&
|
|
1281
|
+
(await client.chats.get(chat))?.person === by.id,
|
|
1282
|
+
},
|
|
1283
|
+
};
|
|
1284
|
+
/**
|
|
1285
|
+
* A follow's run id (`SanomaClient.follow`): `follow:` and the SHA-256 of the event as its schema
|
|
1286
|
+
* parsed it, its keys then in the schema's order, so one event is one id however its JSON was laid out.
|
|
1287
|
+
*/
|
|
1288
|
+
const followRunId = (parsed) => `follow:${createHash("sha256").update(JSON.stringify(parsed)).digest("hex")}`;
|
|
1276
1289
|
/** A change's first run's id: `change:<draft id>`. */
|
|
1277
1290
|
const changeRunId = (id) => `change:${id}`;
|
|
1278
1291
|
/** True when `runId` is a run of the draft `id`'s change: `change:<id>` or `change:<id>~<n>`. */
|