@lunora/agent 1.0.0-alpha.3 → 1.0.0-alpha.5
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/channels.d.mts +39 -31
- package/dist/channels.d.ts +39 -31
- package/dist/channels.mjs +1 -1
- package/dist/component.d.mts +57 -68
- package/dist/component.d.ts +57 -68
- package/dist/component.mjs +20 -9
- package/dist/inbound.d.mts +20 -20
- package/dist/inbound.d.ts +20 -20
- package/dist/index.d.mts +474 -490
- package/dist/index.d.ts +474 -490
- package/dist/index.mjs +4 -4
- package/dist/naming.d.mts +19 -19
- package/dist/naming.d.ts +19 -19
- package/dist/packem_shared/{agentAsTool-Dt8NlU6k.mjs → agentAsTool-CUHlWsmt.mjs} +5 -1
- package/dist/packem_shared/{compileAgentWorkflow-BxJjHgtD.mjs → compileAgentWorkflow-DX90058f.mjs} +1 -1
- package/dist/packem_shared/{defineAgent-D6maSbVc.mjs → defineAgent-DAwAZC9P.mjs} +1 -1
- package/dist/packem_shared/{graph-component-aoUwO-f0.mjs → graph-component-Bbaxxymp.mjs} +3 -2
- package/dist/packem_shared/{normalizeEntityName-CyEEWFkR.mjs → normalizeEntityName-BouctxLC.mjs} +1 -1
- package/dist/packem_shared/{runAgentLoop-Dhg4ZNvw.mjs → runAgentLoop-B3Q2o-Uz.mjs} +1 -1
- package/dist/packem_shared/types.d-boAM2Yi1.d.mts +1114 -0
- package/dist/packem_shared/types.d-boAM2Yi1.d.ts +1114 -0
- package/dist/sandbox.d.mts +126 -122
- package/dist/sandbox.d.ts +126 -122
- package/dist/sandbox.mjs +5 -1
- package/dist/telemetry/index.d.mts +103 -103
- package/dist/telemetry/index.d.ts +103 -103
- package/package.json +8 -8
- package/dist/packem_shared/types.d-BhJFTvz_.d.mts +0 -1114
- package/dist/packem_shared/types.d-BhJFTvz_.d.ts +0 -1114
package/dist/channels.d.mts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { A as AgentDefinition } from "./packem_shared/types.d-
|
|
2
|
-
export type { I as InboundChannelEvent } from "./packem_shared/types.d-
|
|
1
|
+
import { A as AgentDefinition } from "./packem_shared/types.d-boAM2Yi1.mjs";
|
|
2
|
+
export type { I as InboundChannelEvent } from "./packem_shared/types.d-boAM2Yi1.mjs";
|
|
3
3
|
import '@lunora/mail/inbound';
|
|
4
4
|
import 'ai';
|
|
5
5
|
/**
|
|
6
|
-
* Verify a Slack request signature (`x-slack-signature` = `v0=` + HMAC over
|
|
7
|
-
* `v0:timestamp:body`), rejecting a stale timestamp to bound replay. `now` is
|
|
8
|
-
* injectable for deterministic tests (defaults to the wall clock).
|
|
9
|
-
* @experimental
|
|
10
|
-
*/
|
|
6
|
+
* Verify a Slack request signature (`x-slack-signature` = `v0=` + HMAC over
|
|
7
|
+
* `v0:timestamp:body`), rejecting a stale timestamp to bound replay. `now` is
|
|
8
|
+
* injectable for deterministic tests (defaults to the wall clock).
|
|
9
|
+
* @experimental
|
|
10
|
+
*/
|
|
11
11
|
declare const verifySlack: (options: {
|
|
12
12
|
body: string;
|
|
13
13
|
now?: number;
|
|
@@ -17,19 +17,19 @@ declare const verifySlack: (options: {
|
|
|
17
17
|
tolerance?: number;
|
|
18
18
|
}) => Promise<boolean>;
|
|
19
19
|
/**
|
|
20
|
-
* Verify a GitHub webhook signature (`x-hub-signature-256` = `sha256=` + HMAC over the body).
|
|
21
|
-
* @experimental
|
|
22
|
-
*/
|
|
20
|
+
* Verify a GitHub webhook signature (`x-hub-signature-256` = `sha256=` + HMAC over the body).
|
|
21
|
+
* @experimental
|
|
22
|
+
*/
|
|
23
23
|
declare const verifyGithub: (options: {
|
|
24
24
|
body: string;
|
|
25
25
|
secret: string;
|
|
26
26
|
signature: string | undefined;
|
|
27
27
|
}) => Promise<boolean>;
|
|
28
28
|
/**
|
|
29
|
-
* Verify a Discord interaction signature: Ed25519 over `timestamp + body`,
|
|
30
|
-
* `x-signature-ed25519` (hex) against the application's `publicKey` (hex).
|
|
31
|
-
* @experimental
|
|
32
|
-
*/
|
|
29
|
+
* Verify a Discord interaction signature: Ed25519 over `timestamp + body`,
|
|
30
|
+
* `x-signature-ed25519` (hex) against the application's `publicKey` (hex).
|
|
31
|
+
* @experimental
|
|
32
|
+
*/
|
|
33
33
|
declare const verifyDiscord: (options: {
|
|
34
34
|
body: string;
|
|
35
35
|
publicKey: string;
|
|
@@ -37,9 +37,9 @@ declare const verifyDiscord: (options: {
|
|
|
37
37
|
timestamp: string | undefined;
|
|
38
38
|
}) => Promise<boolean>;
|
|
39
39
|
/**
|
|
40
|
-
* One agent wired into the inbound channel HTTP handler.
|
|
41
|
-
* @experimental
|
|
42
|
-
*/
|
|
40
|
+
* One agent wired into the inbound channel HTTP handler.
|
|
41
|
+
* @experimental
|
|
42
|
+
*/
|
|
43
43
|
interface AgentChannelTarget {
|
|
44
44
|
/** The agent definition — only its `onInbound` config is read. */
|
|
45
45
|
agent: Pick<AgentDefinition, "onInbound">;
|
|
@@ -47,20 +47,28 @@ interface AgentChannelTarget {
|
|
|
47
47
|
binding: string;
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
|
-
* The HTTP handler `dispatchAgentChannel` returns — mount it on a webhook route.
|
|
51
|
-
* @experimental
|
|
52
|
-
*/
|
|
50
|
+
* The HTTP handler `dispatchAgentChannel` returns — mount it on a webhook route.
|
|
51
|
+
* @experimental
|
|
52
|
+
*/
|
|
53
53
|
type InboundChannelHandler = (request: Request, env: Record<string, unknown>) => Promise<Response>;
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
*
|
|
64
|
-
|
|
55
|
+
* Whether a `workflow.create()` rejection is a duplicate-instance-id error — the
|
|
56
|
+
* idempotency signal — as opposed to a transient/config failure (Workflows
|
|
57
|
+
* service error, instance-creation quota, bad params). Only the former may be
|
|
58
|
+
* acked; every other failure MUST surface so the handler returns non-2xx and the
|
|
59
|
+
* provider redelivers, rather than silently dropping the event.
|
|
60
|
+
*/
|
|
61
|
+
declare const isDuplicateInstanceError: (error: unknown) => boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Build an HTTP handler that starts a durable agent run from a verified inbound
|
|
64
|
+
* webhook. The channel is detected from the signature headers; EACH eligible
|
|
65
|
+
* target is verified against ITS OWN secret before its mapper is offered the
|
|
66
|
+
* event (so one app's valid signature can't trigger another app's agent), and
|
|
67
|
+
* the first target that both verifies and claims starts a run on its Workflow
|
|
68
|
+
* binding. Returns `401` when NO target's signature verifies, `200` on a claim
|
|
69
|
+
* (or a Discord PONG), `204` when a verified event is declined by every mapper,
|
|
70
|
+
* and `400` for an unrecognized webhook.
|
|
71
|
+
* @experimental
|
|
72
|
+
*/
|
|
65
73
|
declare const dispatchAgentChannel: (targets: ReadonlyArray<AgentChannelTarget>) => InboundChannelHandler;
|
|
66
|
-
export { type AgentChannelTarget, type InboundChannelHandler, dispatchAgentChannel, verifyDiscord, verifyGithub, verifySlack };
|
|
74
|
+
export { type AgentChannelTarget, type InboundChannelHandler, dispatchAgentChannel, isDuplicateInstanceError, verifyDiscord, verifyGithub, verifySlack };
|
package/dist/channels.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { A as AgentDefinition } from "./packem_shared/types.d-
|
|
2
|
-
export type { I as InboundChannelEvent } from "./packem_shared/types.d-
|
|
1
|
+
import { A as AgentDefinition } from "./packem_shared/types.d-boAM2Yi1.js";
|
|
2
|
+
export type { I as InboundChannelEvent } from "./packem_shared/types.d-boAM2Yi1.js";
|
|
3
3
|
import '@lunora/mail/inbound';
|
|
4
4
|
import 'ai';
|
|
5
5
|
/**
|
|
6
|
-
* Verify a Slack request signature (`x-slack-signature` = `v0=` + HMAC over
|
|
7
|
-
* `v0:timestamp:body`), rejecting a stale timestamp to bound replay. `now` is
|
|
8
|
-
* injectable for deterministic tests (defaults to the wall clock).
|
|
9
|
-
* @experimental
|
|
10
|
-
*/
|
|
6
|
+
* Verify a Slack request signature (`x-slack-signature` = `v0=` + HMAC over
|
|
7
|
+
* `v0:timestamp:body`), rejecting a stale timestamp to bound replay. `now` is
|
|
8
|
+
* injectable for deterministic tests (defaults to the wall clock).
|
|
9
|
+
* @experimental
|
|
10
|
+
*/
|
|
11
11
|
declare const verifySlack: (options: {
|
|
12
12
|
body: string;
|
|
13
13
|
now?: number;
|
|
@@ -17,19 +17,19 @@ declare const verifySlack: (options: {
|
|
|
17
17
|
tolerance?: number;
|
|
18
18
|
}) => Promise<boolean>;
|
|
19
19
|
/**
|
|
20
|
-
* Verify a GitHub webhook signature (`x-hub-signature-256` = `sha256=` + HMAC over the body).
|
|
21
|
-
* @experimental
|
|
22
|
-
*/
|
|
20
|
+
* Verify a GitHub webhook signature (`x-hub-signature-256` = `sha256=` + HMAC over the body).
|
|
21
|
+
* @experimental
|
|
22
|
+
*/
|
|
23
23
|
declare const verifyGithub: (options: {
|
|
24
24
|
body: string;
|
|
25
25
|
secret: string;
|
|
26
26
|
signature: string | undefined;
|
|
27
27
|
}) => Promise<boolean>;
|
|
28
28
|
/**
|
|
29
|
-
* Verify a Discord interaction signature: Ed25519 over `timestamp + body`,
|
|
30
|
-
* `x-signature-ed25519` (hex) against the application's `publicKey` (hex).
|
|
31
|
-
* @experimental
|
|
32
|
-
*/
|
|
29
|
+
* Verify a Discord interaction signature: Ed25519 over `timestamp + body`,
|
|
30
|
+
* `x-signature-ed25519` (hex) against the application's `publicKey` (hex).
|
|
31
|
+
* @experimental
|
|
32
|
+
*/
|
|
33
33
|
declare const verifyDiscord: (options: {
|
|
34
34
|
body: string;
|
|
35
35
|
publicKey: string;
|
|
@@ -37,9 +37,9 @@ declare const verifyDiscord: (options: {
|
|
|
37
37
|
timestamp: string | undefined;
|
|
38
38
|
}) => Promise<boolean>;
|
|
39
39
|
/**
|
|
40
|
-
* One agent wired into the inbound channel HTTP handler.
|
|
41
|
-
* @experimental
|
|
42
|
-
*/
|
|
40
|
+
* One agent wired into the inbound channel HTTP handler.
|
|
41
|
+
* @experimental
|
|
42
|
+
*/
|
|
43
43
|
interface AgentChannelTarget {
|
|
44
44
|
/** The agent definition — only its `onInbound` config is read. */
|
|
45
45
|
agent: Pick<AgentDefinition, "onInbound">;
|
|
@@ -47,20 +47,28 @@ interface AgentChannelTarget {
|
|
|
47
47
|
binding: string;
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
|
-
* The HTTP handler `dispatchAgentChannel` returns — mount it on a webhook route.
|
|
51
|
-
* @experimental
|
|
52
|
-
*/
|
|
50
|
+
* The HTTP handler `dispatchAgentChannel` returns — mount it on a webhook route.
|
|
51
|
+
* @experimental
|
|
52
|
+
*/
|
|
53
53
|
type InboundChannelHandler = (request: Request, env: Record<string, unknown>) => Promise<Response>;
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
*
|
|
64
|
-
|
|
55
|
+
* Whether a `workflow.create()` rejection is a duplicate-instance-id error — the
|
|
56
|
+
* idempotency signal — as opposed to a transient/config failure (Workflows
|
|
57
|
+
* service error, instance-creation quota, bad params). Only the former may be
|
|
58
|
+
* acked; every other failure MUST surface so the handler returns non-2xx and the
|
|
59
|
+
* provider redelivers, rather than silently dropping the event.
|
|
60
|
+
*/
|
|
61
|
+
declare const isDuplicateInstanceError: (error: unknown) => boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Build an HTTP handler that starts a durable agent run from a verified inbound
|
|
64
|
+
* webhook. The channel is detected from the signature headers; EACH eligible
|
|
65
|
+
* target is verified against ITS OWN secret before its mapper is offered the
|
|
66
|
+
* event (so one app's valid signature can't trigger another app's agent), and
|
|
67
|
+
* the first target that both verifies and claims starts a run on its Workflow
|
|
68
|
+
* binding. Returns `401` when NO target's signature verifies, `200` on a claim
|
|
69
|
+
* (or a Discord PONG), `204` when a verified event is declined by every mapper,
|
|
70
|
+
* and `400` for an unrecognized webhook.
|
|
71
|
+
* @experimental
|
|
72
|
+
*/
|
|
65
73
|
declare const dispatchAgentChannel: (targets: ReadonlyArray<AgentChannelTarget>) => InboundChannelHandler;
|
|
66
|
-
export { type AgentChannelTarget, type InboundChannelHandler, dispatchAgentChannel, verifyDiscord, verifyGithub, verifySlack };
|
|
74
|
+
export { type AgentChannelTarget, type InboundChannelHandler, dispatchAgentChannel, isDuplicateInstanceError, verifyDiscord, verifyGithub, verifySlack };
|
package/dist/channels.mjs
CHANGED
|
@@ -178,4 +178,4 @@ const dispatchAgentChannel = (targets) => async (request, env) => {
|
|
|
178
178
|
return verifiedAny ? new Response(void 0, { status: 204 }) : new Response("Invalid signature", { status: 401 });
|
|
179
179
|
};
|
|
180
180
|
|
|
181
|
-
export { dispatchAgentChannel, verifyDiscord, verifyGithub, verifySlack };
|
|
181
|
+
export { dispatchAgentChannel, isDuplicateInstanceError, verifyDiscord, verifyGithub, verifySlack };
|
package/dist/component.d.mts
CHANGED
|
@@ -1,33 +1,29 @@
|
|
|
1
1
|
import { SchemaExtension } from '@lunora/server';
|
|
2
2
|
/**
|
|
3
|
-
* Loose structural view of a registered Lunora function — wide enough for any
|
|
4
|
-
* concrete `RegisteredMutation`/`RegisteredQuery` (whose precise validator-map
|
|
5
|
-
* generics make them invariant), narrow enough for re-export, dispatch, and
|
|
6
|
-
* tests. Codegen registers the runtime value; it never needs the generics.
|
|
7
|
-
*/
|
|
3
|
+
* Loose structural view of a registered Lunora function — wide enough for any
|
|
4
|
+
* concrete `RegisteredMutation`/`RegisteredQuery` (whose precise validator-map
|
|
5
|
+
* generics make them invariant), narrow enough for re-export, dispatch, and
|
|
6
|
+
* tests. Codegen registers the runtime value; it never needs the generics.
|
|
7
|
+
*/
|
|
8
8
|
interface AgentRegisteredFunction {
|
|
9
9
|
readonly args: unknown;
|
|
10
10
|
readonly handler: (context: unknown, args: never) => unknown;
|
|
11
11
|
readonly kind: "mutation" | "query";
|
|
12
12
|
readonly visibility?: "internal" | "public";
|
|
13
13
|
}
|
|
14
|
-
/** Stamp a registered function internal — server-side callable only. */
|
|
15
|
-
|
|
16
14
|
/**
|
|
17
|
-
* The per-owner dedup key for an entity name: trim, collapse internal
|
|
18
|
-
* whitespace, lowercase. Deterministic (no locale) so a workflow replay or
|
|
19
|
-
* retry writes the exact same key — the graph upsert stays idempotent.
|
|
20
|
-
* @experimental
|
|
21
|
-
*/
|
|
15
|
+
* The per-owner dedup key for an entity name: trim, collapse internal
|
|
16
|
+
* whitespace, lowercase. Deterministic (no locale) so a workflow replay or
|
|
17
|
+
* retry writes the exact same key — the graph upsert stays idempotent.
|
|
18
|
+
* @experimental
|
|
19
|
+
*/
|
|
22
20
|
declare const normalizeEntityName: (name: string) => string;
|
|
23
|
-
/** The two internal graph-memory functions the durable loop dispatches to. */
|
|
24
|
-
|
|
25
21
|
/**
|
|
26
|
-
* Loose structural view of the registered sandbox action — wide enough for the
|
|
27
|
-
* concrete `RegisteredAction`, narrow enough for re-export + dispatch. Codegen
|
|
28
|
-
* registers the runtime value; it never needs the precise generics.
|
|
29
|
-
* @experimental
|
|
30
|
-
*/
|
|
22
|
+
* Loose structural view of the registered sandbox action — wide enough for the
|
|
23
|
+
* concrete `RegisteredAction`, narrow enough for re-export + dispatch. Codegen
|
|
24
|
+
* registers the runtime value; it never needs the precise generics.
|
|
25
|
+
* @experimental
|
|
26
|
+
*/
|
|
31
27
|
interface SandboxRegisteredFunction {
|
|
32
28
|
readonly args: unknown;
|
|
33
29
|
readonly handler: (context: unknown, args: never) => unknown;
|
|
@@ -35,50 +31,43 @@ interface SandboxRegisteredFunction {
|
|
|
35
31
|
readonly visibility?: "internal" | "public";
|
|
36
32
|
}
|
|
37
33
|
/**
|
|
38
|
-
* `SandboxComponent` is part of the experimental `@lunora/agent` API and may change without a major version bump.
|
|
39
|
-
* @experimental
|
|
40
|
-
*/
|
|
34
|
+
* `SandboxComponent` is part of the experimental `@lunora/agent` API and may change without a major version bump.
|
|
35
|
+
* @experimental
|
|
36
|
+
*/
|
|
41
37
|
interface SandboxComponent {
|
|
42
38
|
invoke: SandboxRegisteredFunction;
|
|
43
39
|
}
|
|
44
40
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
* batteries-included `browserTool`/`containerTool` dispatch to. Codegen
|
|
54
|
-
* auto-registers it at `sandbox:invoke` whenever `lunora/` imports a sandbox
|
|
55
|
-
* tool. It runs as an **action** because that is the only ctx codegen attaches
|
|
56
|
-
* `ctx.browser` to (and `ctx.containers` rides every ctx once a container is
|
|
57
|
-
* declared) — the durable tool step itself has neither.
|
|
58
|
-
* @experimental
|
|
59
|
-
*/
|
|
41
|
+
* Build the sandbox runtime component: the single internal action the
|
|
42
|
+
* batteries-included `browserTool`/`containerTool` dispatch to. Codegen
|
|
43
|
+
* auto-registers it at `sandbox:invoke` whenever `lunora/` imports a sandbox
|
|
44
|
+
* tool. It runs as an **action** because that is the only ctx codegen attaches
|
|
45
|
+
* `ctx.browser` to (and `ctx.containers` rides every ctx once a container is
|
|
46
|
+
* declared) — the durable tool step itself has neither.
|
|
47
|
+
* @experimental
|
|
48
|
+
*/
|
|
60
49
|
declare const sandboxComponent: () => SandboxComponent;
|
|
61
50
|
/**
|
|
62
|
-
* The agent thread tables, shipped as a schema extension so an app merges
|
|
63
|
-
* them with one call and they can never collide with app tables:
|
|
64
|
-
*
|
|
65
|
-
* ```ts
|
|
66
|
-
* // lunora/schema.ts
|
|
67
|
-
* export default defineSchema({ ... }).extend(agentExtension);
|
|
68
|
-
* ```
|
|
69
|
-
*
|
|
70
|
-
* Message ordering follows the Convex-agent model: `seq` is the monotonic
|
|
71
|
-
* per-thread position (allocated from the thread's `messageCount` counter, so
|
|
72
|
-
* allocation is O(1) inside the serialized mutation), and `messageKey` is the
|
|
73
|
-
* deterministic idempotency key — a workflow replay that re-persists the same
|
|
74
|
-
* message is a no-op instead of a duplicate.
|
|
75
|
-
* @experimental
|
|
76
|
-
*/
|
|
51
|
+
* The agent thread tables, shipped as a schema extension so an app merges
|
|
52
|
+
* them with one call and they can never collide with app tables:
|
|
53
|
+
*
|
|
54
|
+
* ```ts
|
|
55
|
+
* // lunora/schema.ts
|
|
56
|
+
* export default defineSchema({ ... }).extend(agentExtension);
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* Message ordering follows the Convex-agent model: `seq` is the monotonic
|
|
60
|
+
* per-thread position (allocated from the thread's `messageCount` counter, so
|
|
61
|
+
* allocation is O(1) inside the serialized mutation), and `messageKey` is the
|
|
62
|
+
* deterministic idempotency key — a workflow replay that re-persists the same
|
|
63
|
+
* message is a no-op instead of a duplicate.
|
|
64
|
+
* @experimental
|
|
65
|
+
*/
|
|
77
66
|
declare const agentExtension: SchemaExtension;
|
|
78
67
|
/**
|
|
79
|
-
* `AgentComponent` is part of the experimental `@lunora/agent` API and may change without a major version bump.
|
|
80
|
-
* @experimental
|
|
81
|
-
*/
|
|
68
|
+
* `AgentComponent` is part of the experimental `@lunora/agent` API and may change without a major version bump.
|
|
69
|
+
* @experimental
|
|
70
|
+
*/
|
|
82
71
|
interface AgentComponent {
|
|
83
72
|
extension: SchemaExtension;
|
|
84
73
|
functions: {
|
|
@@ -98,18 +87,18 @@ interface AgentComponent {
|
|
|
98
87
|
};
|
|
99
88
|
}
|
|
100
89
|
/**
|
|
101
|
-
* Build the agent runtime component: the thread schema extension plus the
|
|
102
|
-
* functions the durable loop dispatches to (and the client subscribes to).
|
|
103
|
-
* Codegen auto-registers them under the `agents:*` namespace whenever
|
|
104
|
-
* `lunora/agents.ts` declares an agent — the loop's dispatch paths assume
|
|
105
|
-
* that namespace, and apps never re-export these by hand.
|
|
106
|
-
*
|
|
107
|
-
* Most mutations are **internal** (only the workflow's admin-authenticated
|
|
108
|
-
* dispatch may call them); the queries are public so a client can subscribe
|
|
109
|
-
* to `agents:agentMessages` for a live thread view. Two mutations are public:
|
|
110
|
-
* `agentResolveApproval` (a client resolves a HITL approval) and `agentRun`
|
|
111
|
-
* (an HTTP client starts a durable run) — both owner-gated.
|
|
112
|
-
* @experimental
|
|
113
|
-
*/
|
|
90
|
+
* Build the agent runtime component: the thread schema extension plus the
|
|
91
|
+
* functions the durable loop dispatches to (and the client subscribes to).
|
|
92
|
+
* Codegen auto-registers them under the `agents:*` namespace whenever
|
|
93
|
+
* `lunora/agents.ts` declares an agent — the loop's dispatch paths assume
|
|
94
|
+
* that namespace, and apps never re-export these by hand.
|
|
95
|
+
*
|
|
96
|
+
* Most mutations are **internal** (only the workflow's admin-authenticated
|
|
97
|
+
* dispatch may call them); the queries are public so a client can subscribe
|
|
98
|
+
* to `agents:agentMessages` for a live thread view. Two mutations are public:
|
|
99
|
+
* `agentResolveApproval` (a client resolves a HITL approval) and `agentRun`
|
|
100
|
+
* (an HTTP client starts a durable run) — both owner-gated.
|
|
101
|
+
* @experimental
|
|
102
|
+
*/
|
|
114
103
|
declare const agentComponent: () => AgentComponent;
|
|
115
104
|
export { AgentComponent, type SandboxComponent, type SandboxRegisteredFunction, agentComponent, agentExtension, normalizeEntityName, sandboxComponent };
|
package/dist/component.d.ts
CHANGED
|
@@ -1,33 +1,29 @@
|
|
|
1
1
|
import { SchemaExtension } from '@lunora/server';
|
|
2
2
|
/**
|
|
3
|
-
* Loose structural view of a registered Lunora function — wide enough for any
|
|
4
|
-
* concrete `RegisteredMutation`/`RegisteredQuery` (whose precise validator-map
|
|
5
|
-
* generics make them invariant), narrow enough for re-export, dispatch, and
|
|
6
|
-
* tests. Codegen registers the runtime value; it never needs the generics.
|
|
7
|
-
*/
|
|
3
|
+
* Loose structural view of a registered Lunora function — wide enough for any
|
|
4
|
+
* concrete `RegisteredMutation`/`RegisteredQuery` (whose precise validator-map
|
|
5
|
+
* generics make them invariant), narrow enough for re-export, dispatch, and
|
|
6
|
+
* tests. Codegen registers the runtime value; it never needs the generics.
|
|
7
|
+
*/
|
|
8
8
|
interface AgentRegisteredFunction {
|
|
9
9
|
readonly args: unknown;
|
|
10
10
|
readonly handler: (context: unknown, args: never) => unknown;
|
|
11
11
|
readonly kind: "mutation" | "query";
|
|
12
12
|
readonly visibility?: "internal" | "public";
|
|
13
13
|
}
|
|
14
|
-
/** Stamp a registered function internal — server-side callable only. */
|
|
15
|
-
|
|
16
14
|
/**
|
|
17
|
-
* The per-owner dedup key for an entity name: trim, collapse internal
|
|
18
|
-
* whitespace, lowercase. Deterministic (no locale) so a workflow replay or
|
|
19
|
-
* retry writes the exact same key — the graph upsert stays idempotent.
|
|
20
|
-
* @experimental
|
|
21
|
-
*/
|
|
15
|
+
* The per-owner dedup key for an entity name: trim, collapse internal
|
|
16
|
+
* whitespace, lowercase. Deterministic (no locale) so a workflow replay or
|
|
17
|
+
* retry writes the exact same key — the graph upsert stays idempotent.
|
|
18
|
+
* @experimental
|
|
19
|
+
*/
|
|
22
20
|
declare const normalizeEntityName: (name: string) => string;
|
|
23
|
-
/** The two internal graph-memory functions the durable loop dispatches to. */
|
|
24
|
-
|
|
25
21
|
/**
|
|
26
|
-
* Loose structural view of the registered sandbox action — wide enough for the
|
|
27
|
-
* concrete `RegisteredAction`, narrow enough for re-export + dispatch. Codegen
|
|
28
|
-
* registers the runtime value; it never needs the precise generics.
|
|
29
|
-
* @experimental
|
|
30
|
-
*/
|
|
22
|
+
* Loose structural view of the registered sandbox action — wide enough for the
|
|
23
|
+
* concrete `RegisteredAction`, narrow enough for re-export + dispatch. Codegen
|
|
24
|
+
* registers the runtime value; it never needs the precise generics.
|
|
25
|
+
* @experimental
|
|
26
|
+
*/
|
|
31
27
|
interface SandboxRegisteredFunction {
|
|
32
28
|
readonly args: unknown;
|
|
33
29
|
readonly handler: (context: unknown, args: never) => unknown;
|
|
@@ -35,50 +31,43 @@ interface SandboxRegisteredFunction {
|
|
|
35
31
|
readonly visibility?: "internal" | "public";
|
|
36
32
|
}
|
|
37
33
|
/**
|
|
38
|
-
* `SandboxComponent` is part of the experimental `@lunora/agent` API and may change without a major version bump.
|
|
39
|
-
* @experimental
|
|
40
|
-
*/
|
|
34
|
+
* `SandboxComponent` is part of the experimental `@lunora/agent` API and may change without a major version bump.
|
|
35
|
+
* @experimental
|
|
36
|
+
*/
|
|
41
37
|
interface SandboxComponent {
|
|
42
38
|
invoke: SandboxRegisteredFunction;
|
|
43
39
|
}
|
|
44
40
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
* batteries-included `browserTool`/`containerTool` dispatch to. Codegen
|
|
54
|
-
* auto-registers it at `sandbox:invoke` whenever `lunora/` imports a sandbox
|
|
55
|
-
* tool. It runs as an **action** because that is the only ctx codegen attaches
|
|
56
|
-
* `ctx.browser` to (and `ctx.containers` rides every ctx once a container is
|
|
57
|
-
* declared) — the durable tool step itself has neither.
|
|
58
|
-
* @experimental
|
|
59
|
-
*/
|
|
41
|
+
* Build the sandbox runtime component: the single internal action the
|
|
42
|
+
* batteries-included `browserTool`/`containerTool` dispatch to. Codegen
|
|
43
|
+
* auto-registers it at `sandbox:invoke` whenever `lunora/` imports a sandbox
|
|
44
|
+
* tool. It runs as an **action** because that is the only ctx codegen attaches
|
|
45
|
+
* `ctx.browser` to (and `ctx.containers` rides every ctx once a container is
|
|
46
|
+
* declared) — the durable tool step itself has neither.
|
|
47
|
+
* @experimental
|
|
48
|
+
*/
|
|
60
49
|
declare const sandboxComponent: () => SandboxComponent;
|
|
61
50
|
/**
|
|
62
|
-
* The agent thread tables, shipped as a schema extension so an app merges
|
|
63
|
-
* them with one call and they can never collide with app tables:
|
|
64
|
-
*
|
|
65
|
-
* ```ts
|
|
66
|
-
* // lunora/schema.ts
|
|
67
|
-
* export default defineSchema({ ... }).extend(agentExtension);
|
|
68
|
-
* ```
|
|
69
|
-
*
|
|
70
|
-
* Message ordering follows the Convex-agent model: `seq` is the monotonic
|
|
71
|
-
* per-thread position (allocated from the thread's `messageCount` counter, so
|
|
72
|
-
* allocation is O(1) inside the serialized mutation), and `messageKey` is the
|
|
73
|
-
* deterministic idempotency key — a workflow replay that re-persists the same
|
|
74
|
-
* message is a no-op instead of a duplicate.
|
|
75
|
-
* @experimental
|
|
76
|
-
*/
|
|
51
|
+
* The agent thread tables, shipped as a schema extension so an app merges
|
|
52
|
+
* them with one call and they can never collide with app tables:
|
|
53
|
+
*
|
|
54
|
+
* ```ts
|
|
55
|
+
* // lunora/schema.ts
|
|
56
|
+
* export default defineSchema({ ... }).extend(agentExtension);
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* Message ordering follows the Convex-agent model: `seq` is the monotonic
|
|
60
|
+
* per-thread position (allocated from the thread's `messageCount` counter, so
|
|
61
|
+
* allocation is O(1) inside the serialized mutation), and `messageKey` is the
|
|
62
|
+
* deterministic idempotency key — a workflow replay that re-persists the same
|
|
63
|
+
* message is a no-op instead of a duplicate.
|
|
64
|
+
* @experimental
|
|
65
|
+
*/
|
|
77
66
|
declare const agentExtension: SchemaExtension;
|
|
78
67
|
/**
|
|
79
|
-
* `AgentComponent` is part of the experimental `@lunora/agent` API and may change without a major version bump.
|
|
80
|
-
* @experimental
|
|
81
|
-
*/
|
|
68
|
+
* `AgentComponent` is part of the experimental `@lunora/agent` API and may change without a major version bump.
|
|
69
|
+
* @experimental
|
|
70
|
+
*/
|
|
82
71
|
interface AgentComponent {
|
|
83
72
|
extension: SchemaExtension;
|
|
84
73
|
functions: {
|
|
@@ -98,18 +87,18 @@ interface AgentComponent {
|
|
|
98
87
|
};
|
|
99
88
|
}
|
|
100
89
|
/**
|
|
101
|
-
* Build the agent runtime component: the thread schema extension plus the
|
|
102
|
-
* functions the durable loop dispatches to (and the client subscribes to).
|
|
103
|
-
* Codegen auto-registers them under the `agents:*` namespace whenever
|
|
104
|
-
* `lunora/agents.ts` declares an agent — the loop's dispatch paths assume
|
|
105
|
-
* that namespace, and apps never re-export these by hand.
|
|
106
|
-
*
|
|
107
|
-
* Most mutations are **internal** (only the workflow's admin-authenticated
|
|
108
|
-
* dispatch may call them); the queries are public so a client can subscribe
|
|
109
|
-
* to `agents:agentMessages` for a live thread view. Two mutations are public:
|
|
110
|
-
* `agentResolveApproval` (a client resolves a HITL approval) and `agentRun`
|
|
111
|
-
* (an HTTP client starts a durable run) — both owner-gated.
|
|
112
|
-
* @experimental
|
|
113
|
-
*/
|
|
90
|
+
* Build the agent runtime component: the thread schema extension plus the
|
|
91
|
+
* functions the durable loop dispatches to (and the client subscribes to).
|
|
92
|
+
* Codegen auto-registers them under the `agents:*` namespace whenever
|
|
93
|
+
* `lunora/agents.ts` declares an agent — the loop's dispatch paths assume
|
|
94
|
+
* that namespace, and apps never re-export these by hand.
|
|
95
|
+
*
|
|
96
|
+
* Most mutations are **internal** (only the workflow's admin-authenticated
|
|
97
|
+
* dispatch may call them); the queries are public so a client can subscribe
|
|
98
|
+
* to `agents:agentMessages` for a live thread view. Two mutations are public:
|
|
99
|
+
* `agentResolveApproval` (a client resolves a HITL approval) and `agentRun`
|
|
100
|
+
* (an HTTP client starts a durable run) — both owner-gated.
|
|
101
|
+
* @experimental
|
|
102
|
+
*/
|
|
114
103
|
declare const agentComponent: () => AgentComponent;
|
|
115
104
|
export { AgentComponent, type SandboxComponent, type SandboxRegisteredFunction, agentComponent, agentExtension, normalizeEntityName, sandboxComponent };
|
package/dist/component.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LunoraError } from '@lunora/errors';
|
|
2
2
|
import { defineTable, initLunora, defineSchemaExtension } from '@lunora/server';
|
|
3
3
|
import { v } from '@lunora/values';
|
|
4
|
-
import { a as asInternal, A as AGENT_EXTENSION_KEY, g as graphTables, d as definedColumns, b as graphComponent } from './packem_shared/graph-component-
|
|
5
|
-
export { n as normalizeEntityName } from './packem_shared/graph-component-
|
|
4
|
+
import { a as asInternal, A as AGENT_EXTENSION_KEY, g as graphTables, d as definedColumns, b as graphComponent } from './packem_shared/graph-component-Bbaxxymp.mjs';
|
|
5
|
+
export { n as normalizeEntityName } from './packem_shared/graph-component-Bbaxxymp.mjs';
|
|
6
6
|
export { sandboxComponent } from './packem_shared/sandboxComponent-DR3pTwBL.mjs';
|
|
7
7
|
|
|
8
8
|
const EPISODES_TABLE = "agent_episodes";
|
|
@@ -179,7 +179,7 @@ const agentComponent = () => {
|
|
|
179
179
|
throw new Error(`@lunora/agent: thread "${args.key}" belongs to another owner`);
|
|
180
180
|
}
|
|
181
181
|
const priorInstanceId = existing["instanceId"];
|
|
182
|
-
const isConcurrentRun = (existing["status"] === "running" || existing["status"] === "awaiting_input") && priorInstanceId !== void 0 && args.instanceId
|
|
182
|
+
const isConcurrentRun = (existing["status"] === "running" || existing["status"] === "awaiting_input") && priorInstanceId !== void 0 && (args.instanceId === void 0 || args.instanceId !== priorInstanceId);
|
|
183
183
|
if (isConcurrentRun) {
|
|
184
184
|
const policy = args.onConcurrentRun ?? "reject";
|
|
185
185
|
if (policy !== "replace") {
|
|
@@ -188,7 +188,12 @@ const agentComponent = () => {
|
|
|
188
188
|
`@lunora/agent: thread "${args.key}" already has a run in flight (instance "${priorInstanceId}") — onConcurrentRun="${policy}"`
|
|
189
189
|
);
|
|
190
190
|
}
|
|
191
|
-
await context.db.patch(existing["_id"], {
|
|
191
|
+
await context.db.patch(existing["_id"], {
|
|
192
|
+
error: void 0,
|
|
193
|
+
status: "running",
|
|
194
|
+
updatedAt: now,
|
|
195
|
+
...args.instanceId === void 0 ? {} : { instanceId: args.instanceId }
|
|
196
|
+
});
|
|
192
197
|
return { created: false, priorInstanceId, replaced: true };
|
|
193
198
|
}
|
|
194
199
|
await context.db.patch(existing["_id"], {
|
|
@@ -310,9 +315,11 @@ const agentComponent = () => {
|
|
|
310
315
|
if (readableThread(thread, context.auth) === void 0) {
|
|
311
316
|
return [];
|
|
312
317
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
318
|
+
if (args.limit !== void 0) {
|
|
319
|
+
const tail = await context.db.query(MESSAGES_TABLE).withIndex("byThread", (q) => q.eq("threadKey", args.key)).order("desc").take(args.limit);
|
|
320
|
+
return tail.toReversed();
|
|
321
|
+
}
|
|
322
|
+
return context.db.query(MESSAGES_TABLE).withIndex("byThread", (q) => q.eq("threadKey", args.key)).collect();
|
|
316
323
|
});
|
|
317
324
|
const agentResolveApproval = mutation.input({
|
|
318
325
|
decision: v.union(v.literal("approve"), v.literal("reject")),
|
|
@@ -326,6 +333,9 @@ const agentComponent = () => {
|
|
|
326
333
|
if (readable === void 0) {
|
|
327
334
|
throw new LunoraError("FORBIDDEN", `@lunora/agent: not allowed to resolve approvals on thread "${args.threadKey}"`);
|
|
328
335
|
}
|
|
336
|
+
if (readable["instanceId"] !== args.instanceId) {
|
|
337
|
+
throw new LunoraError("FORBIDDEN", `@lunora/agent: instance "${args.instanceId}" does not own thread "${args.threadKey}"`);
|
|
338
|
+
}
|
|
329
339
|
const agentName = readable["agent"];
|
|
330
340
|
const { agents } = context;
|
|
331
341
|
const handle = agents?.[agentName];
|
|
@@ -336,8 +346,9 @@ const agentComponent = () => {
|
|
|
336
346
|
);
|
|
337
347
|
}
|
|
338
348
|
await handle.sendEvent(args.instanceId, {
|
|
339
|
-
payload: { decision: args.decision, ...args.note === void 0 ? {} : { note: args.note } },
|
|
340
|
-
|
|
349
|
+
payload: { decision: args.decision, toolCallId: args.toolCallId, ...args.note === void 0 ? {} : { note: args.note } },
|
|
350
|
+
// Scoped per tool call — see the doc comment above.
|
|
351
|
+
type: `agent-approval:${args.toolCallId}`
|
|
341
352
|
});
|
|
342
353
|
return { resolved: true };
|
|
343
354
|
});
|