@pylonsync/functions 0.20.0 → 0.22.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/dist/agent.d.ts +27 -6
- package/dist/define.d.ts +2 -1
- package/dist/index.d.ts +3 -2
- package/dist/response.d.ts +39 -0
- package/dist/runtime.d.ts +3 -1
- package/dist/ssr-runtime.d.ts +7 -0
- package/dist/types.d.ts +260 -13
- package/dist/workflows.d.ts +19 -2
- package/package.json +1 -1
- package/src/agent-internals.ts +5 -0
- package/src/agent.test.ts +205 -0
- package/src/agent.ts +220 -99
- package/src/define.ts +2 -1
- package/src/index.ts +10 -0
- package/src/response.test.ts +42 -0
- package/src/response.ts +109 -0
- package/src/runtime-llm-stream.test.ts +85 -0
- package/src/runtime.ts +206 -10
- package/src/ssr-runtime.test.ts +25 -0
- package/src/ssr-runtime.ts +35 -3
- package/src/types.ts +266 -13
- package/src/workflows.test.ts +74 -7
- package/src/workflows.ts +81 -19
package/dist/agent.d.ts
CHANGED
|
@@ -36,6 +36,20 @@
|
|
|
36
36
|
* including tool calls, with zero extra plumbing.
|
|
37
37
|
*/
|
|
38
38
|
import type { ActionCtx, AnyValidator, FnDefinition, ValidatorSchema } from "./types";
|
|
39
|
+
/** The run a tool call belongs to: the third argument of every tool
|
|
40
|
+
* handler. */
|
|
41
|
+
export interface AgentToolRun {
|
|
42
|
+
runId: string;
|
|
43
|
+
/** The agent's name (its file name in `functions/`). */
|
|
44
|
+
agent: string;
|
|
45
|
+
/** The user the run belongs to. */
|
|
46
|
+
userId: string | null;
|
|
47
|
+
/** The `context` server code passed to `ctx.agents.run`, or the one
|
|
48
|
+
* stored on the run by an earlier `ctx.agents.run`. `null` when the
|
|
49
|
+
* run has none (a run a client started with `streamFn`). Set only by
|
|
50
|
+
* server code, so a tool can trust it to identify what it acts on. */
|
|
51
|
+
context: Record<string, unknown> | null;
|
|
52
|
+
}
|
|
39
53
|
/** One tool an agent can call. */
|
|
40
54
|
export interface AgentTool {
|
|
41
55
|
/** Shown to the model — say when to use the tool, not how it works. */
|
|
@@ -45,10 +59,11 @@ export interface AgentTool {
|
|
|
45
59
|
* a tool_result error the model can react to. Omit for no-arg tools. */
|
|
46
60
|
args?: ValidatorSchema;
|
|
47
61
|
/** Runs with the agent action's ctx (runQuery/runMutation, llm,
|
|
48
|
-
* email, …).
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
|
|
62
|
+
* email, …). `run` identifies the run, including the server-set
|
|
63
|
+
* `context` from `ctx.agents.run`. The return value is
|
|
64
|
+
* JSON-serialized into the tool_result the model sees. Throwing marks
|
|
65
|
+
* the result is_error — the model sees the message and can recover. */
|
|
66
|
+
handler: (ctx: ActionCtx, input: Record<string, unknown>, run: AgentToolRun) => unknown;
|
|
52
67
|
}
|
|
53
68
|
export interface AgentDefinition {
|
|
54
69
|
/** System prompt. A function receives the ctx + call args for
|
|
@@ -83,8 +98,10 @@ export interface AgentCallArgs {
|
|
|
83
98
|
/** Optional display title, stored on new runs. */
|
|
84
99
|
title?: string;
|
|
85
100
|
/** Ask the run to stop. Requires `runId`, ignores `input`, and
|
|
86
|
-
* returns as soon as the request is recorded
|
|
87
|
-
*
|
|
101
|
+
* returns as soon as the request is recorded. The running loop
|
|
102
|
+
* notices within a few seconds: a model response in progress is
|
|
103
|
+
* aborted (the provider stops generating), and a running tool sees
|
|
104
|
+
* `ctx.signal` abort. */
|
|
88
105
|
cancel?: boolean;
|
|
89
106
|
}
|
|
90
107
|
/** What the agent action resolves with (also the `event: result`
|
|
@@ -115,5 +132,9 @@ export declare function validatorSchemaToJsonSchema(schema: ValidatorSchema): Re
|
|
|
115
132
|
/** Marker so the SDK's discoverFunctions can detect agents and inject
|
|
116
133
|
* the AgentRun/AgentMessage entities into the manifest. */
|
|
117
134
|
export declare const AGENT_MARKER = "__pylonAgent";
|
|
135
|
+
/** ctx key the runtime sets when server code started this call with
|
|
136
|
+
* `ctx.agents.run`: `{ context }`. A symbol, so no JSON a client sends
|
|
137
|
+
* can set it. */
|
|
138
|
+
export declare const AGENT_INVOCATION: unique symbol;
|
|
118
139
|
export declare function agent(def: AgentDefinition): FnDefinition<AgentCallArgs, AgentResult>;
|
|
119
140
|
export declare function isAgentDefinition(value: unknown): boolean;
|
package/dist/define.d.ts
CHANGED
|
@@ -44,7 +44,8 @@ interface CommonDef<TSchema extends ValidatorSchema | undefined = ValidatorSchem
|
|
|
44
44
|
* IDLE-timeout SECONDS for this function: how long it may go without
|
|
45
45
|
* producing any activity (a stream chunk, a `ctx.db` op, an LLM
|
|
46
46
|
* event) before the host cancels the call. Defaults to
|
|
47
|
-
* `PYLON_FN_CALL_TIMEOUT` (30s
|
|
47
|
+
* `PYLON_FN_CALL_TIMEOUT` (30s; Stack0 Cloud sets 300s). Activity
|
|
48
|
+
* restarts the budget, so a
|
|
48
49
|
* streaming agent run stays alive as long as it keeps producing; a
|
|
49
50
|
* silent hang is cancelled at the budget. Total lifetime is capped at
|
|
50
51
|
* 10× this value however chatty the call is.
|
package/dist/index.d.ts
CHANGED
|
@@ -20,10 +20,11 @@
|
|
|
20
20
|
export { query, mutation, action } from "./define";
|
|
21
21
|
export { v } from "./validators";
|
|
22
22
|
export { workflow } from "./workflows";
|
|
23
|
+
export type { RawResponse, RawResponseInit } from "./response";
|
|
23
24
|
export { agent, isAgentDefinition, validatorToJsonSchema, validatorSchemaToJsonSchema, } from "./agent";
|
|
24
|
-
export type { AgentDefinition, AgentTool, AgentCallArgs, AgentResult, } from "./agent";
|
|
25
|
+
export type { AgentDefinition, AgentTool, AgentToolRun, AgentCallArgs, AgentResult, } from "./agent";
|
|
25
26
|
export type { WorkflowDefinition, WorkflowRun, WorkflowRunRequest, WorkflowRunnerResponse, WorkflowStepResult, } from "./workflows";
|
|
26
27
|
export { resetDb, installTestIsolation } from "./testing";
|
|
27
28
|
export { slugifyName, availableSlug } from "./slugify";
|
|
28
29
|
export type { SsrResponse, SsrCookieOptions, SsrMetadata, Sitemap, SitemapEntry, Robots, RobotsRule, } from "./ssr-runtime";
|
|
29
|
-
export type { QueryCtx, MutationCtx, ActionCtx, DbReader, DbWriter, Stream, Scheduler, AuthInfo, AuthMode, AuthRequirement, FnDefinition, Validator, AnyValidator, ValidatorSchema, InferValidator, InferArgs, RequireMember, RequireMemberOptions, Shards, ShardsReader, ShardsWriter, ShardInfo, ShardTransfer, MemberRow, Workflows, VectorSearchQuery, VectorSearchResult, SearchResult, PaginationResult, Llm, LlmMessage, LlmContentBlock, LlmTool, LlmCompleteRequest, LlmCompleteResponse, LlmStreamEvent, Rooms, Domains, TenantDomainResult, TenantDomainDns, DomainAvailability, DomainContact, RegisterDomainOptions, RegisteredDomainResult, } from "./types";
|
|
30
|
+
export type { QueryCtx, MutationCtx, ActionCtx, DbReader, DbWriter, Stream, Scheduler, AuthInfo, AuthMode, AuthRequirement, FnDefinition, Validator, AnyValidator, ValidatorSchema, InferValidator, InferArgs, RequireMember, RequireMemberOptions, Shards, ShardsReader, ShardsWriter, ShardInfo, ShardTransfer, MemberRow, Workflows, WorkflowRunSummary, WorkflowRunStatus, Audit, AuditLog, AuditEntry, Agents, AgentRunOptions, VectorSearchQuery, VectorSearchResult, SearchResult, PaginationResult, Llm, LlmMessage, LlmContentBlock, LlmTool, LlmCompleteRequest, LlmCompleteResponse, LlmStreamEvent, Rooms, Domains, TenantDomainResult, TenantDomainRecord, TenantDomainDns, DomainAvailability, DomainContact, RegisterDomainOptions, RegisteredDomainResult, } from "./types";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raw HTTP responses from webhook actions.
|
|
3
|
+
*
|
|
4
|
+
* An action called through `/api/webhooks/<name>` normally answers with its
|
|
5
|
+
* return value as JSON and status 200. Returning `ctx.response(...)` sends
|
|
6
|
+
* the given status, content type, headers, and body instead. Every other
|
|
7
|
+
* route (`/api/fn/<name>`, `ctx.runAction`) returns the value as ordinary
|
|
8
|
+
* JSON data.
|
|
9
|
+
*
|
|
10
|
+
* The host enforces the same rules (crates/router/src/raw_response.rs), so
|
|
11
|
+
* a hand-built object cannot bypass them. The two header lists must stay in
|
|
12
|
+
* sync.
|
|
13
|
+
*/
|
|
14
|
+
/** What `ctx.response` accepts. */
|
|
15
|
+
export interface RawResponseInit {
|
|
16
|
+
/** HTTP status, 200-599. Default 200. */
|
|
17
|
+
status?: number;
|
|
18
|
+
/** Shorthand for the `Content-Type` header. Default `text/plain; charset=utf-8`. */
|
|
19
|
+
contentType?: string;
|
|
20
|
+
/** Extra response headers. Values must be visible ASCII. */
|
|
21
|
+
headers?: Record<string, string>;
|
|
22
|
+
/** Response body. Default empty. Must be empty for 204, 205, and 304. */
|
|
23
|
+
body?: string;
|
|
24
|
+
}
|
|
25
|
+
/** The marked value an action returns. Build it with `ctx.response`. */
|
|
26
|
+
export interface RawResponse {
|
|
27
|
+
readonly __pylonResponse: 1;
|
|
28
|
+
readonly status: number;
|
|
29
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
30
|
+
readonly body: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build a raw HTTP response for a webhook action to return.
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* return ctx.response({ contentType: "text/xml", body: "<Response/>" });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function response(init?: RawResponseInit): RawResponse;
|
package/dist/runtime.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* each ctx.db / ctx.scheduler / ctx.runMutation call), so the map never
|
|
15
15
|
* needs to queue multiple RPCs per call_id.
|
|
16
16
|
*/
|
|
17
|
-
import type { DbReader, DbWriter, Llm, Rooms, Workflows } from "./types";
|
|
17
|
+
import type { DbReader, DbWriter, Llm, Rooms, Workflows, Audit } from "./types";
|
|
18
18
|
export declare function buildDbReader(callId: string, ssrRead?: boolean): DbReader;
|
|
19
19
|
export declare function buildSsrFnCaller(callId: string): (name: string, args?: Record<string, unknown>) => Promise<unknown>;
|
|
20
20
|
export declare function buildDbWriter(callId: string): DbWriter;
|
|
@@ -46,4 +46,6 @@ export declare function buildRooms(callId: string): Rooms;
|
|
|
46
46
|
* takes it from there, so `start` returns the instance id immediately.
|
|
47
47
|
* Uses the queued call_id-keyed `rpc` (the reply carries no op_id).
|
|
48
48
|
*/
|
|
49
|
+
/** Build `ctx.audit` — round-trips `audit_op` frames to the host. */
|
|
50
|
+
export declare function buildAudit(callId: string): Audit;
|
|
49
51
|
export declare function buildWorkflows(callId: string): Workflows;
|
package/dist/ssr-runtime.d.ts
CHANGED
|
@@ -337,6 +337,13 @@ export declare function moduleExistsIn(fs: any, path: any, cwd: string, dir: str
|
|
|
337
337
|
* in the process.
|
|
338
338
|
*/
|
|
339
339
|
export declare function findBoundaryIn(fs: any, path: any, cwd: string, componentPath: string, fileName: string): string | null;
|
|
340
|
+
/** Loopback host? `host` is a lowercase authority (`host[:port]`,
|
|
341
|
+
* `[ipv6]:port`). True for exactly `localhost`, dotted 127.0.0.0/8
|
|
342
|
+
* without leading zeros, `::1`, or `0.0.0.0`, with an optional numeric
|
|
343
|
+
* port. The match is exact, so
|
|
344
|
+
* `localhost.example.com` is not loopback. Mirrors `is_loopback_host` in
|
|
345
|
+
* crates/router/src/public_url.rs. Exported for tests. */
|
|
346
|
+
export declare function isLoopbackHost(host: string): boolean;
|
|
340
347
|
/** Pure origin resolution (exported for tests).
|
|
341
348
|
*
|
|
342
349
|
* SECURITY: the request `Host` (and `X-Forwarded-Proto`) is attacker-
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Type definitions for the function system.
|
|
3
3
|
*/
|
|
4
|
+
import type { RawResponse, RawResponseInit } from "./response";
|
|
4
5
|
/**
|
|
5
6
|
* Declarative auth requirement for a function. The framework
|
|
6
7
|
* enforces this BEFORE the handler runs — if the caller doesn't
|
|
@@ -296,8 +297,23 @@ export interface Scheduler {
|
|
|
296
297
|
runAfter(delayMs: number, fnName: string, args: Record<string, unknown>): Promise<string>;
|
|
297
298
|
/** Schedule a function to run at a specific time (Unix ms). */
|
|
298
299
|
runAt(timestamp: number, fnName: string, args: Record<string, unknown>): Promise<string>;
|
|
299
|
-
/**
|
|
300
|
-
|
|
300
|
+
/**
|
|
301
|
+
* Cancel a scheduled function that has not started. Pass the id
|
|
302
|
+
* `runAfter` or `runAt` returned.
|
|
303
|
+
*
|
|
304
|
+
* Resolves `{ cancelled: true }` when the job will not run, and
|
|
305
|
+
* `{ cancelled: false }` when the id is unknown or the job already
|
|
306
|
+
* started or finished (a running job is not interrupted). Rejects with
|
|
307
|
+
* `SCHEDULE_CANCEL_FAILED` when the cancel could not be saved; the job
|
|
308
|
+
* then still runs.
|
|
309
|
+
*
|
|
310
|
+
* Inside a mutation, the cancel commits or rolls back with the
|
|
311
|
+
* mutation: if the mutation throws, the job stays scheduled. From an
|
|
312
|
+
* action, it takes effect at once.
|
|
313
|
+
*/
|
|
314
|
+
cancel(scheduleId: string): Promise<{
|
|
315
|
+
cancelled: boolean;
|
|
316
|
+
}>;
|
|
301
317
|
}
|
|
302
318
|
/**
|
|
303
319
|
* Transactional email transport.
|
|
@@ -411,16 +427,24 @@ export interface Llm {
|
|
|
411
427
|
* if (res.stop_reason === "tool_use") { ...run tools, loop... }
|
|
412
428
|
* ```
|
|
413
429
|
*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
430
|
+
* The function's call timeout (PYLON_FN_CALL_TIMEOUT, 30s default, or
|
|
431
|
+
* the function's own `timeout`) is an idle timeout. A running stream
|
|
432
|
+
* counts as activity, but no call outlives 10× its timeout, so a long
|
|
433
|
+
* agent run should still declare its own `timeout`.
|
|
434
|
+
*
|
|
435
|
+
* Pass `{ signal }` to stop a stream early. When the signal aborts,
|
|
436
|
+
* the promise rejects with `err.code === "LLM_CANCELLED"` and the
|
|
437
|
+
* server closes the provider connection, so the model stops
|
|
438
|
+
* generating (and billing) tokens. A stream still running when the
|
|
439
|
+
* function returns or times out is cancelled the same way.
|
|
418
440
|
*
|
|
419
441
|
* Same errors and same gating as {@link Llm.complete} — including
|
|
420
442
|
* the model allowlist, so streaming can't be used to reach a model
|
|
421
443
|
* `complete` would refuse.
|
|
422
444
|
*/
|
|
423
|
-
stream(request: LlmCompleteRequest, onEvent: (event: LlmStreamEvent) => void
|
|
445
|
+
stream(request: LlmCompleteRequest, onEvent: (event: LlmStreamEvent) => void, options?: {
|
|
446
|
+
signal?: AbortSignal;
|
|
447
|
+
}): Promise<LlmCompleteResponse>;
|
|
424
448
|
/**
|
|
425
449
|
* Batch-embed texts via the configured embeddings provider. One
|
|
426
450
|
* embedding per input, in input order. Pair with a
|
|
@@ -523,18 +547,153 @@ export interface Workflows {
|
|
|
523
547
|
/**
|
|
524
548
|
* Start a workflow instance by name. Returns immediately with the
|
|
525
549
|
* instance id — the engine's background driver executes the steps.
|
|
550
|
+
*
|
|
551
|
+
* With `key` (for example a lead id), at most one non-terminal run
|
|
552
|
+
* exists per workflow name and key. If one exists, no new run starts
|
|
553
|
+
* and its id is returned with `created: false`. A finished run frees
|
|
554
|
+
* the key.
|
|
526
555
|
*/
|
|
527
|
-
start(name: string, input?: unknown
|
|
556
|
+
start(name: string, input?: unknown, opts?: {
|
|
557
|
+
key?: string;
|
|
558
|
+
}): Promise<{
|
|
528
559
|
id: string;
|
|
560
|
+
created: boolean;
|
|
529
561
|
}>;
|
|
530
562
|
/**
|
|
531
|
-
*
|
|
532
|
-
* `wf.waitForEvent(event)
|
|
533
|
-
*
|
|
563
|
+
* Send an event to a run. If the run is waiting for it
|
|
564
|
+
* (`wf.waitForEvent(event)`), the run resumes and `delivered` is true.
|
|
565
|
+
* Otherwise the event is buffered (`buffered: true`) and the run's next
|
|
566
|
+
* `waitForEvent(event)` consumes it. Rejects when the run has finished
|
|
567
|
+
* or already holds 100 buffered events. Events sent without data
|
|
568
|
+
* arrive as `{}`.
|
|
534
569
|
*/
|
|
535
570
|
sendEvent(workflowId: string, event: string, data?: unknown): Promise<{
|
|
536
571
|
delivered: boolean;
|
|
572
|
+
buffered: boolean;
|
|
537
573
|
}>;
|
|
574
|
+
/**
|
|
575
|
+
* Cancel a run. No further step runs. A step already in progress may
|
|
576
|
+
* finish, but its result is discarded. Resolves `cancelled: false` when
|
|
577
|
+
* the run had already finished. Rejects for an unknown id.
|
|
578
|
+
*/
|
|
579
|
+
cancel(workflowId: string, opts?: {
|
|
580
|
+
reason?: string;
|
|
581
|
+
}): Promise<{
|
|
582
|
+
cancelled: boolean;
|
|
583
|
+
}>;
|
|
584
|
+
/** Read one run, or null if the id is unknown. */
|
|
585
|
+
get(workflowId: string): Promise<WorkflowRunSummary | null>;
|
|
586
|
+
/**
|
|
587
|
+
* List runs, newest first. `status: "active"` matches every
|
|
588
|
+
* non-terminal status. `limit` defaults to 100 (max 1000).
|
|
589
|
+
*
|
|
590
|
+
* ```ts
|
|
591
|
+
* // Seller texted STOP: end every cadence for the lead.
|
|
592
|
+
* const runs = await ctx.workflows.list({ key: leadId, status: "active" });
|
|
593
|
+
* for (const run of runs) {
|
|
594
|
+
* await ctx.workflows.cancel(run.id, { reason: "STOP" });
|
|
595
|
+
* }
|
|
596
|
+
* ```
|
|
597
|
+
*/
|
|
598
|
+
list(filter?: {
|
|
599
|
+
name?: string;
|
|
600
|
+
key?: string;
|
|
601
|
+
status?: WorkflowRunStatus | "active";
|
|
602
|
+
limit?: number;
|
|
603
|
+
}): Promise<WorkflowRunSummary[]>;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* The application audit log (`ctx.audit` on mutations and actions).
|
|
607
|
+
* Append-only, stored with the auth audit events.
|
|
608
|
+
*/
|
|
609
|
+
export interface AuditLog {
|
|
610
|
+
/**
|
|
611
|
+
* Record an event. The actor and tenant come from the caller's session.
|
|
612
|
+
* `action` is a short dotted name (`lead.export`, `script.update`) and
|
|
613
|
+
* is stored as `app.<action>`. `meta` values are stored as strings
|
|
614
|
+
* (non-strings as JSON text); keep secrets out of it.
|
|
615
|
+
*
|
|
616
|
+
* Inside a mutation the event is written after the mutation commits and
|
|
617
|
+
* dropped if it rolls back. Rejects with `AUDIT_WRITE_FAILED` when an
|
|
618
|
+
* action's event could not be stored.
|
|
619
|
+
*/
|
|
620
|
+
log(event: {
|
|
621
|
+
action: string;
|
|
622
|
+
entity?: string;
|
|
623
|
+
entityId?: string;
|
|
624
|
+
/** The user the event is about, when not the actor. */
|
|
625
|
+
subject?: string;
|
|
626
|
+
meta?: Record<string, unknown>;
|
|
627
|
+
}): Promise<{
|
|
628
|
+
id: string;
|
|
629
|
+
}>;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* `ctx.audit` on actions: {@link AuditLog.log} plus reads. Mutations get
|
|
633
|
+
* only `log`: in a Postgres mutation the transaction holds a connection,
|
|
634
|
+
* and a read would need a second.
|
|
635
|
+
*/
|
|
636
|
+
export interface Audit extends AuditLog {
|
|
637
|
+
/**
|
|
638
|
+
* Read events, newest first. A caller with a tenant reads that tenant's
|
|
639
|
+
* events; a caller without one reads only events it performed. Admin
|
|
640
|
+
* callers may pass `tenant` or read all tenants. `action` matches
|
|
641
|
+
* `lead.export` as `app.lead.export`; framework actions
|
|
642
|
+
* (`entity.update`, `retention.delete`) and auth action names match as
|
|
643
|
+
* given. `limit` defaults to 100 (max 1000). To page,
|
|
644
|
+
* pass `beforeId` set to the last event's `id`. `before` (unix seconds)
|
|
645
|
+
* limits by time.
|
|
646
|
+
*/
|
|
647
|
+
list(filter?: {
|
|
648
|
+
entity?: string;
|
|
649
|
+
entityId?: string;
|
|
650
|
+
actor?: string;
|
|
651
|
+
action?: string;
|
|
652
|
+
tenant?: string;
|
|
653
|
+
before?: number;
|
|
654
|
+
beforeId?: string;
|
|
655
|
+
limit?: number;
|
|
656
|
+
}): Promise<AuditEntry[]>;
|
|
657
|
+
}
|
|
658
|
+
export interface AuditEntry {
|
|
659
|
+
id: string;
|
|
660
|
+
/** Unix seconds. */
|
|
661
|
+
createdAt: number;
|
|
662
|
+
/** `app.<action>`, `entity.insert|update|delete`, `retention.delete`, or an auth action. */
|
|
663
|
+
action: string;
|
|
664
|
+
actor: string | null;
|
|
665
|
+
subject: string | null;
|
|
666
|
+
tenant: string | null;
|
|
667
|
+
entity: string | null;
|
|
668
|
+
entityId: string | null;
|
|
669
|
+
ip: string | null;
|
|
670
|
+
success: boolean;
|
|
671
|
+
reason: string | null;
|
|
672
|
+
/** For `entity.*` events, `fields` lists the changed field names. */
|
|
673
|
+
meta: Record<string, string>;
|
|
674
|
+
}
|
|
675
|
+
export type WorkflowRunStatus = "pending" | "running" | "sleeping" | "waiting" | "completed" | "failed" | "cancelled";
|
|
676
|
+
/** A workflow run without its step history. Times are unix seconds. */
|
|
677
|
+
export interface WorkflowRunSummary {
|
|
678
|
+
id: string;
|
|
679
|
+
name: string;
|
|
680
|
+
key: string | null;
|
|
681
|
+
status: WorkflowRunStatus;
|
|
682
|
+
input: unknown;
|
|
683
|
+
output: unknown;
|
|
684
|
+
error: string | null;
|
|
685
|
+
cancelReason: string | null;
|
|
686
|
+
/** Event name the run is waiting for, when `status` is "waiting". */
|
|
687
|
+
waitingFor: string | null;
|
|
688
|
+
/** When the current wait times out, if it has a timeout. */
|
|
689
|
+
waitDeadline: number | null;
|
|
690
|
+
/** When the current sleep ends. */
|
|
691
|
+
wakeAt: number | null;
|
|
692
|
+
/** Events sent but not yet consumed by a `waitForEvent`. */
|
|
693
|
+
bufferedEvents: number;
|
|
694
|
+
createdAt: number | null;
|
|
695
|
+
startedAt: number | null;
|
|
696
|
+
completedAt: number | null;
|
|
538
697
|
}
|
|
539
698
|
export interface LlmMessage {
|
|
540
699
|
role: "user" | "assistant" | "system" | "tool";
|
|
@@ -915,6 +1074,8 @@ export interface MutationCtx<R extends AuthRequirement = "optional"> {
|
|
|
915
1074
|
connections: Connections;
|
|
916
1075
|
/** Durable workflows: start / deliver events — see {@link Workflows}. */
|
|
917
1076
|
workflows: Workflows;
|
|
1077
|
+
/** Application audit log (write only in mutations) — see {@link AuditLog}. */
|
|
1078
|
+
audit: AuditLog;
|
|
918
1079
|
/** Signed file-download URLs — see {@link Files}. */
|
|
919
1080
|
files: Files;
|
|
920
1081
|
/** Shard tickets, reads, and inputs after the commit — see {@link Shards}. */
|
|
@@ -947,8 +1108,18 @@ export interface TenantDomainResult {
|
|
|
947
1108
|
status: string;
|
|
948
1109
|
/** Whether the hostname + TLS certificate are both active. */
|
|
949
1110
|
active?: boolean;
|
|
950
|
-
/**
|
|
951
|
-
|
|
1111
|
+
/**
|
|
1112
|
+
* True for an apex domain (`acme.com`). An apex cannot be a CNAME, so the
|
|
1113
|
+
* customer adds A/AAAA records pointing at the app instead.
|
|
1114
|
+
*/
|
|
1115
|
+
apex?: boolean;
|
|
1116
|
+
/**
|
|
1117
|
+
* Every DNS record the customer adds, for both kinds of domain: a CNAME
|
|
1118
|
+
* (subdomain) or A/AAAA (apex), plus ownership and certificate records.
|
|
1119
|
+
*/
|
|
1120
|
+
records?: TenantDomainRecord[];
|
|
1121
|
+
/** The CNAME the customer points a subdomain at; null for an apex. */
|
|
1122
|
+
cnameTarget: string | null;
|
|
952
1123
|
/** TXT record proving domain ownership before DNS cutover (or null). */
|
|
953
1124
|
ownership: TenantDomainDns | null;
|
|
954
1125
|
/** TXT records that issue the DV certificate. */
|
|
@@ -956,6 +1127,13 @@ export interface TenantDomainResult {
|
|
|
956
1127
|
/** Human-readable provisioning errors, empty when healthy. */
|
|
957
1128
|
errors: string[];
|
|
958
1129
|
}
|
|
1130
|
+
export interface TenantDomainRecord {
|
|
1131
|
+
type: "A" | "AAAA" | "CNAME" | "TXT";
|
|
1132
|
+
name: string;
|
|
1133
|
+
value: string;
|
|
1134
|
+
/** What the record is for, to show the customer. */
|
|
1135
|
+
purpose: string;
|
|
1136
|
+
}
|
|
959
1137
|
/**
|
|
960
1138
|
* Platform domains: attach / register / detach custom domains for your app's
|
|
961
1139
|
* OWN end-customers, so each tenant can reach your app on their own hostname.
|
|
@@ -1067,6 +1245,49 @@ export interface Domains {
|
|
|
1067
1245
|
* itself serve the app — attach a host with `add()` afterward. */
|
|
1068
1246
|
register(domainName: string, opts?: RegisterDomainOptions): Promise<RegisteredDomainResult>;
|
|
1069
1247
|
}
|
|
1248
|
+
/** Options for {@link Agents.run}. */
|
|
1249
|
+
export interface AgentRunOptions {
|
|
1250
|
+
/** The message for this turn. */
|
|
1251
|
+
input: string;
|
|
1252
|
+
/** Continue this run. It must belong to `as.userId` and this agent. */
|
|
1253
|
+
runId?: string;
|
|
1254
|
+
/** Display title, stored on a new run. */
|
|
1255
|
+
title?: string;
|
|
1256
|
+
/**
|
|
1257
|
+
* The user the run belongs to and runs as. The run shows up in that
|
|
1258
|
+
* user's synced `AgentRun`/`AgentMessage` rows. `admin: true` also
|
|
1259
|
+
* gives the run admin rights (needed for an agent declared
|
|
1260
|
+
* `auth: "admin"`), and is allowed only when the caller is an admin.
|
|
1261
|
+
*/
|
|
1262
|
+
as: {
|
|
1263
|
+
userId: string;
|
|
1264
|
+
admin?: boolean;
|
|
1265
|
+
};
|
|
1266
|
+
/**
|
|
1267
|
+
* JSON the agent's tool handlers receive as `run.context` (their third
|
|
1268
|
+
* argument), for example the conversation a webhook turn belongs to.
|
|
1269
|
+
* Stored on the run as `AgentRun.context`, so later turns of the run
|
|
1270
|
+
* see it too. The run's owner can read it; do not put secrets in it.
|
|
1271
|
+
*/
|
|
1272
|
+
context?: Record<string, unknown>;
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Run an `agent()` from server code. See {@link ActionCtx.agents}.
|
|
1276
|
+
*/
|
|
1277
|
+
export interface Agents {
|
|
1278
|
+
/**
|
|
1279
|
+
* Run agent `name` (its file name in `functions/`) as `options.as`.
|
|
1280
|
+
* Resolves with the agent's result once the turn finishes, like a
|
|
1281
|
+
* `streamFn` call's final `result` event. The agent's tokens are not
|
|
1282
|
+
* streamed to this caller; they are in the run's `AgentMessage` rows.
|
|
1283
|
+
*
|
|
1284
|
+
* Only server code can do this: the calling action must be
|
|
1285
|
+
* `internal: true` (jobs, workflows, scheduled work) or run with admin
|
|
1286
|
+
* rights (an admin session, or a webhook after `ctx.auth.elevate`).
|
|
1287
|
+
* Otherwise it throws `AGENT_RUN_FORBIDDEN`.
|
|
1288
|
+
*/
|
|
1289
|
+
run(name: string, options: AgentRunOptions): Promise<import("./agent").AgentResult>;
|
|
1290
|
+
}
|
|
1070
1291
|
export interface ActionCtx<R extends AuthRequirement = "optional"> {
|
|
1071
1292
|
auth: AuthInfo<R>;
|
|
1072
1293
|
stream: Stream;
|
|
@@ -1081,6 +1302,10 @@ export interface ActionCtx<R extends AuthRequirement = "optional"> {
|
|
|
1081
1302
|
connections: Connections;
|
|
1082
1303
|
/** Durable workflows: start / deliver events — see {@link Workflows}. */
|
|
1083
1304
|
workflows: Workflows;
|
|
1305
|
+
/** Application audit log — see {@link Audit}. */
|
|
1306
|
+
audit: Audit;
|
|
1307
|
+
/** Run an `agent()` as a named user from server code — see {@link Agents}. */
|
|
1308
|
+
agents: Agents;
|
|
1084
1309
|
/** Attach / register custom domains for your app's OWN end-customers
|
|
1085
1310
|
* (platform domains) — see {@link Domains}. Cloud-only. */
|
|
1086
1311
|
domains: Domains;
|
|
@@ -1125,12 +1350,34 @@ export interface ActionCtx<R extends AuthRequirement = "optional"> {
|
|
|
1125
1350
|
* ```
|
|
1126
1351
|
*/
|
|
1127
1352
|
request?: RequestInfo;
|
|
1353
|
+
/**
|
|
1354
|
+
* Build a raw HTTP response. When an action called through
|
|
1355
|
+
* `/api/webhooks/<name>` returns it, the route sends this status,
|
|
1356
|
+
* content type, headers, and body instead of JSON. Other routes return
|
|
1357
|
+
* it as ordinary JSON data. Throws on an invalid status or header.
|
|
1358
|
+
*
|
|
1359
|
+
* ```ts
|
|
1360
|
+
* // Twilio expects TwiML, not JSON.
|
|
1361
|
+
* return ctx.response({ contentType: "text/xml", body: "<Response/>" });
|
|
1362
|
+
* ```
|
|
1363
|
+
*/
|
|
1364
|
+
response(init?: RawResponseInit): RawResponse;
|
|
1128
1365
|
}
|
|
1129
1366
|
/** HTTP request metadata available on an action's ctx when invoked via an
|
|
1130
1367
|
* HTTP route binding. Header names are lowercased. */
|
|
1131
1368
|
export interface RequestInfo {
|
|
1132
1369
|
method: string;
|
|
1370
|
+
/** Request path with the query string, as received. */
|
|
1133
1371
|
path: string;
|
|
1372
|
+
/**
|
|
1373
|
+
* The full URL the client requested: scheme, host, path, and query.
|
|
1374
|
+
* Behind a proxy, the host comes from `X-Forwarded-Host` or `Host`
|
|
1375
|
+
* only when it is trusted (loopback, the `PYLON_PUBLIC_URL` host,
|
|
1376
|
+
* `PYLON_CANONICAL_HOST`, a `PYLON_TRUSTED_HOSTS` entry, or one of the
|
|
1377
|
+
* app's domains); otherwise the `PYLON_PUBLIC_URL` origin is used. Use
|
|
1378
|
+
* it to verify providers that sign the whole URL, such as Twilio.
|
|
1379
|
+
*/
|
|
1380
|
+
url: string;
|
|
1134
1381
|
headers: Record<string, string>;
|
|
1135
1382
|
rawBody: string;
|
|
1136
1383
|
}
|
package/dist/workflows.d.ts
CHANGED
|
@@ -57,6 +57,7 @@ export type WorkflowRunnerResponse = {
|
|
|
57
57
|
} | {
|
|
58
58
|
action: "wait_event";
|
|
59
59
|
event: string;
|
|
60
|
+
timeout?: string;
|
|
60
61
|
} | {
|
|
61
62
|
action: "complete";
|
|
62
63
|
output: unknown;
|
|
@@ -80,10 +81,26 @@ export interface WorkflowRun<TInput = unknown> {
|
|
|
80
81
|
/** Pause the workflow for a duration ("30s", "5m", "24h", "7d"). */
|
|
81
82
|
sleep(duration: string): Promise<void>;
|
|
82
83
|
/**
|
|
83
|
-
* Pause until
|
|
84
|
-
* Resolves with the event's data
|
|
84
|
+
* Pause until the event arrives through `ctx.workflows.sendEvent` or
|
|
85
|
+
* `POST /api/workflows/<id>/event`. Resolves with the event's data
|
|
86
|
+
* (`{}` when it was sent without data).
|
|
87
|
+
*
|
|
88
|
+
* Events sent while the run is not waiting for them are buffered. The
|
|
89
|
+
* next `waitForEvent` with that name consumes the oldest buffered
|
|
90
|
+
* event, so an event that arrives during a step is not lost.
|
|
91
|
+
*
|
|
92
|
+
* The same event name can be awaited more than once in a run; each
|
|
93
|
+
* call consumes one event.
|
|
85
94
|
*/
|
|
86
95
|
waitForEvent<T = unknown>(eventName: string): Promise<T>;
|
|
96
|
+
/**
|
|
97
|
+
* Same as above, but resolves with `null` if no event arrives within
|
|
98
|
+
* `timeout` ("60s", "5m", "24h", "7d"). The timeout is durable: it
|
|
99
|
+
* survives restarts, like `sleep`.
|
|
100
|
+
*/
|
|
101
|
+
waitForEvent<T = unknown>(eventName: string, opts: {
|
|
102
|
+
timeout: string;
|
|
103
|
+
}): Promise<T | null>;
|
|
87
104
|
}
|
|
88
105
|
export interface WorkflowDefinition<TInput = unknown> {
|
|
89
106
|
readonly __pylonWorkflow: true;
|
package/package.json
CHANGED
package/src/agent-internals.ts
CHANGED
|
@@ -128,6 +128,10 @@ export function registerAgentInternals(
|
|
|
128
128
|
pendingInput: [],
|
|
129
129
|
cancelRequested: false,
|
|
130
130
|
steps: 0,
|
|
131
|
+
// Only written when present, so an app that declares its own
|
|
132
|
+
// AgentRun without a `context` column keeps working until it
|
|
133
|
+
// uses ctx.agents.run with a context.
|
|
134
|
+
...(args.context != null ? { context: args.context } : {}),
|
|
131
135
|
createdAt: nowIso(),
|
|
132
136
|
updatedAt: nowIso(),
|
|
133
137
|
});
|
|
@@ -188,6 +192,7 @@ export function registerAgentInternals(
|
|
|
188
192
|
if (args.error !== undefined) patch.error = args.error;
|
|
189
193
|
if (args.streamId !== undefined) patch.streamId = args.streamId;
|
|
190
194
|
if (args.steps !== undefined) patch.steps = Number(args.steps) || 0;
|
|
195
|
+
if (args.context != null) patch.context = args.context;
|
|
191
196
|
// Claiming the run starts a new generation, which supersedes
|
|
192
197
|
// a cancel left set by one that died before acting on it.
|
|
193
198
|
// Terminal statuses clear it because it has been honoured.
|