@fungi.computer/oyster 0.4.1 → 0.5.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/agents.d.ts +2 -1
- package/dist/agents.js +63 -8
- package/dist/apps/gate.d.ts +4 -0
- package/dist/apps/gate.js +3 -0
- package/dist/boot-host-script.js +1 -1
- package/dist/build/candidate-cli.mjs +19 -4
- package/dist/channels/binding.d.ts +63 -0
- package/dist/channels/binding.js +85 -0
- package/dist/channels/conversations.d.ts +235 -0
- package/dist/channels/conversations.js +705 -0
- package/dist/channels/ids.d.ts +8 -0
- package/dist/channels/ids.js +15 -0
- package/dist/host.d.ts +1 -1
- package/dist/host.js +21 -4
- package/dist/keys.d.ts +4 -1
- package/dist/keys.js +15 -4
- package/dist/machine-link/authority.d.ts +7 -0
- package/dist/machine-link/delivery.d.ts +12 -0
- package/dist/machine-link/delivery.js +22 -1
- package/dist/machine-link/disposition.d.ts +16 -0
- package/dist/machine-link/disposition.js +65 -0
- package/dist/machine-link/host.d.ts +11 -2
- package/dist/machine-link/host.js +125 -5
- package/dist/machine-link/link.d.ts +4 -0
- package/dist/machine-link/link.js +47 -1
- package/dist/page-script.js +4 -4
- package/dist/standalone/agent-mail.js +4 -1
- package/dist/standalone/agents.d.ts +8 -0
- package/dist/standalone/agents.js +21 -2
- package/dist/standalone/channel-session-door.d.ts +4 -0
- package/dist/standalone/channel-session-door.js +42 -0
- package/dist/standalone/machine-link.d.ts +2 -0
- package/dist/standalone/machine-link.js +34 -1
- package/dist/testing/capabilities.d.ts +2 -0
- package/dist/testing/capabilities.js +3 -1
- package/dist/workers-git.js +1 -1
- package/dist/workers.d.ts +3 -0
- package/docs/api/agents.md +8 -4
- package/docs/api/apps.md +8 -4
- package/docs/api/browser.md +40 -16
- package/docs/api/keys.md +25 -3
- package/docs/api/workers.md +21 -14
- package/docs/site/agent-quickstart.mdx +23 -0
- package/examples/standalone/wrangler.jsonc +3 -4
- package/package.json +28 -16
|
@@ -21740,6 +21740,10 @@ var BirdDogAgentRecipientReferenceSchema = Struct({
|
|
|
21740
21740
|
agentId: Identifier,
|
|
21741
21741
|
sessionId: optionalKey2(Identifier)
|
|
21742
21742
|
});
|
|
21743
|
+
var BirdDogSystemIdentitySchema = Struct({
|
|
21744
|
+
kind: Literal2("system"),
|
|
21745
|
+
systemId: Literal2("hub")
|
|
21746
|
+
});
|
|
21743
21747
|
var BIRD_DOG_DIAGNOSTIC_MAX_LENGTH = 200;
|
|
21744
21748
|
var SettledBirdDogReplySchema = Struct({
|
|
21745
21749
|
commandId: Identifier,
|
|
@@ -21769,6 +21773,14 @@ var BirdDogReplySchema = Union2([
|
|
|
21769
21773
|
UndeliverableBirdDogReplySchema,
|
|
21770
21774
|
AcceptedBirdDogReplySchema
|
|
21771
21775
|
]);
|
|
21776
|
+
var BirdDogAgentReplySchema = Union2([
|
|
21777
|
+
SettledBirdDogReplySchema,
|
|
21778
|
+
AcceptedBirdDogReplySchema,
|
|
21779
|
+
Struct({
|
|
21780
|
+
outcome: Literal2("undeliverable"),
|
|
21781
|
+
reason: Literal2("recipient_left")
|
|
21782
|
+
})
|
|
21783
|
+
]);
|
|
21772
21784
|
var REDACTED = "[redacted]";
|
|
21773
21785
|
var schemeCredential = /\b(bearer|basic)\s+[^\s"',;]+/giu;
|
|
21774
21786
|
var namedCredential = /\b((?:api[_-]?key|access[_-]?token|refresh[_-]?token|token|secret|password|authorization)["']?\s*[:=]\s*["']?)(?!(?:bearer|basic)\s)[^\s"',;&]+/giu;
|
|
@@ -21794,13 +21806,16 @@ var BirdDogMailSchema = Union2([
|
|
|
21794
21806
|
...BirdDogMailFields,
|
|
21795
21807
|
from: BirdDogAgentReferenceSchema,
|
|
21796
21808
|
/** Settlement or acceptance facts, present only on a reply. */
|
|
21797
|
-
reply: optionalKey2(
|
|
21809
|
+
reply: optionalKey2(BirdDogAgentReplySchema)
|
|
21798
21810
|
}),
|
|
21799
21811
|
Struct({
|
|
21800
21812
|
...BirdDogMailFields,
|
|
21801
|
-
from:
|
|
21802
|
-
/**
|
|
21803
|
-
reply:
|
|
21813
|
+
from: BirdDogSystemIdentitySchema,
|
|
21814
|
+
/** Only the Hub may author this offline disposition. */
|
|
21815
|
+
reply: Struct({
|
|
21816
|
+
outcome: Literal2("undeliverable"),
|
|
21817
|
+
reason: Literal2("recipient_offline")
|
|
21818
|
+
})
|
|
21804
21819
|
})
|
|
21805
21820
|
]);
|
|
21806
21821
|
var BirdDogAgentWorkSchema = Struct({
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** The runtime needs a binding, not a Team or an authority projection. */
|
|
3
|
+
export type ConversationBinding = Readonly<{
|
|
4
|
+
bindingId: string;
|
|
5
|
+
lifecycle: "active" | "suspended";
|
|
6
|
+
selector: Readonly<{
|
|
7
|
+
provider: "event";
|
|
8
|
+
target: "new" | "named";
|
|
9
|
+
verifier: "fungi-v1" | "github" | "secret-url";
|
|
10
|
+
eventsPerMinute: number;
|
|
11
|
+
}> | Readonly<{
|
|
12
|
+
provider: "web" | "discord" | "email" | "game";
|
|
13
|
+
}>;
|
|
14
|
+
/** Zod's optional binding projection may carry an explicit undefined. */
|
|
15
|
+
limits?: BindingLimits | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
/** Per-party edge limits applied before any work is accepted. */
|
|
18
|
+
export declare const bindingLimitsSchema: z.ZodObject<{
|
|
19
|
+
messagesPerPartyPerDay: z.ZodNumber;
|
|
20
|
+
charsPerMessage: z.ZodNumber;
|
|
21
|
+
newPartiesPerHour: z.ZodNumber;
|
|
22
|
+
}, z.core.$strict>;
|
|
23
|
+
/** Per-binding edge limits. */
|
|
24
|
+
export type BindingLimits = z.infer<typeof bindingLimitsSchema>;
|
|
25
|
+
/** Edge limits of a binding whose owner set none. */
|
|
26
|
+
export declare const DEFAULT_BINDING_LIMITS: BindingLimits;
|
|
27
|
+
/**
|
|
28
|
+
* How long a GitHub body digest keeps a changed-id replay out: the verifiers'
|
|
29
|
+
* signed-timestamp skew (Veil's `WEBHOOK_SIGNATURE_MAX_SKEW_SECONDS`; a test
|
|
30
|
+
* pins them equal). GitHub signs no timestamp, so this window is the bound.
|
|
31
|
+
*/
|
|
32
|
+
export declare const EVENT_REPLAY_WINDOW_SECONDS = 300;
|
|
33
|
+
/** The edge limits one binding runs under: its owner's, else its kind's default. */
|
|
34
|
+
export declare function limitsOf(binding: ConversationBinding): BindingLimits;
|
|
35
|
+
export declare const discordSnowflakeSchema: z.ZodString;
|
|
36
|
+
/** The party on the other side of a channel conversation; never a member. */
|
|
37
|
+
export declare const channelPartySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
38
|
+
kind: z.ZodLiteral<"visitor">;
|
|
39
|
+
visitorId: z.ZodString;
|
|
40
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
41
|
+
kind: z.ZodLiteral<"discord-user">;
|
|
42
|
+
guildId: z.ZodString;
|
|
43
|
+
userId: z.ZodString;
|
|
44
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
45
|
+
kind: z.ZodLiteral<"email-sender">;
|
|
46
|
+
address: z.ZodEmail;
|
|
47
|
+
dmarc: z.ZodEnum<{
|
|
48
|
+
none: "none";
|
|
49
|
+
pass: "pass";
|
|
50
|
+
fail: "fail";
|
|
51
|
+
}>;
|
|
52
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
53
|
+
kind: z.ZodLiteral<"player">;
|
|
54
|
+
worldId: z.ZodString;
|
|
55
|
+
playerId: z.ZodString;
|
|
56
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
57
|
+
kind: z.ZodLiteral<"source">;
|
|
58
|
+
source: z.ZodString;
|
|
59
|
+
}, z.core.$strict>], "kind">;
|
|
60
|
+
/** One channel party. */
|
|
61
|
+
export type ChannelParty = z.infer<typeof channelPartySchema>;
|
|
62
|
+
/** Short human label for a party, used in author metadata and owner rows. */
|
|
63
|
+
export declare function partyLabel(party: ChannelParty): string;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { channelIds } from "./ids.js";
|
|
3
|
+
/** Per-party edge limits applied before any work is accepted. */
|
|
4
|
+
export const bindingLimitsSchema = z.strictObject({
|
|
5
|
+
messagesPerPartyPerDay: z.number().int().min(1).max(10_000),
|
|
6
|
+
charsPerMessage: z.number().int().min(1).max(16_000),
|
|
7
|
+
newPartiesPerHour: z.number().int().min(1).max(100_000),
|
|
8
|
+
});
|
|
9
|
+
/** Edge limits of a binding whose owner set none. */
|
|
10
|
+
export const DEFAULT_BINDING_LIMITS = Object.freeze({
|
|
11
|
+
messagesPerPartyPerDay: 30,
|
|
12
|
+
charsPerMessage: 4_000,
|
|
13
|
+
newPartiesPerHour: 200,
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* Edge limits of an incoming-events binding whose owner set none. Events are
|
|
17
|
+
* not people: `eventsPerMinute` bounds intake, so the
|
|
18
|
+
* per-party and new-party limits sit at their ceilings, and one event may
|
|
19
|
+
* carry the longest message intake accepts.
|
|
20
|
+
*/
|
|
21
|
+
const DEFAULT_EVENT_LIMITS = Object.freeze({
|
|
22
|
+
messagesPerPartyPerDay: 10_000,
|
|
23
|
+
charsPerMessage: 16_000,
|
|
24
|
+
newPartiesPerHour: 100_000,
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* How long a GitHub body digest keeps a changed-id replay out: the verifiers'
|
|
28
|
+
* signed-timestamp skew (Veil's `WEBHOOK_SIGNATURE_MAX_SKEW_SECONDS`; a test
|
|
29
|
+
* pins them equal). GitHub signs no timestamp, so this window is the bound.
|
|
30
|
+
*/
|
|
31
|
+
export const EVENT_REPLAY_WINDOW_SECONDS = 300;
|
|
32
|
+
/** The edge limits one binding runs under: its owner's, else its kind's default. */
|
|
33
|
+
export function limitsOf(binding) {
|
|
34
|
+
return (binding.limits ??
|
|
35
|
+
(binding.selector.provider === "event"
|
|
36
|
+
? DEFAULT_EVENT_LIMITS
|
|
37
|
+
: DEFAULT_BINDING_LIMITS));
|
|
38
|
+
}
|
|
39
|
+
export const discordSnowflakeSchema = z.string().regex(/^\d{17,20}$/u);
|
|
40
|
+
/** The party on the other side of a channel conversation; never a member. */
|
|
41
|
+
export const channelPartySchema = z.discriminatedUnion("kind", [
|
|
42
|
+
z.strictObject({
|
|
43
|
+
kind: z.literal("visitor"),
|
|
44
|
+
visitorId: z
|
|
45
|
+
.string()
|
|
46
|
+
.refine((value) => channelIds.visitor.is(value), "Invalid visitor"),
|
|
47
|
+
}),
|
|
48
|
+
z.strictObject({
|
|
49
|
+
kind: z.literal("discord-user"),
|
|
50
|
+
guildId: discordSnowflakeSchema,
|
|
51
|
+
userId: discordSnowflakeSchema,
|
|
52
|
+
}),
|
|
53
|
+
z.strictObject({
|
|
54
|
+
kind: z.literal("email-sender"),
|
|
55
|
+
address: z.email(),
|
|
56
|
+
dmarc: z.enum(["pass", "fail", "none"]),
|
|
57
|
+
}),
|
|
58
|
+
z.strictObject({
|
|
59
|
+
kind: z.literal("player"),
|
|
60
|
+
worldId: z.string().min(1).max(160),
|
|
61
|
+
playerId: z.string().min(1).max(160),
|
|
62
|
+
}),
|
|
63
|
+
z.strictObject({
|
|
64
|
+
kind: z.literal("source"),
|
|
65
|
+
/** The sender's declared source identity, such as `github`. */
|
|
66
|
+
source: z.string().regex(/^[a-z0-9][a-z0-9._-]{0,63}$/u),
|
|
67
|
+
}),
|
|
68
|
+
]);
|
|
69
|
+
/** Short human label for a party, used in author metadata and owner rows. */
|
|
70
|
+
export function partyLabel(party) {
|
|
71
|
+
switch (party.kind) {
|
|
72
|
+
case "visitor":
|
|
73
|
+
return `Visitor ${party.visitorId.slice(-4)}`;
|
|
74
|
+
case "discord-user":
|
|
75
|
+
return `Discord user ${party.userId}`;
|
|
76
|
+
case "email-sender":
|
|
77
|
+
return party.dmarc === "pass"
|
|
78
|
+
? party.address
|
|
79
|
+
: `${party.address} (unverified)`;
|
|
80
|
+
case "player":
|
|
81
|
+
return `Player ${party.playerId}`;
|
|
82
|
+
case "source":
|
|
83
|
+
return party.source;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type FungiAuthor, type AuthorMeta, type MessageMetaValue } from "@fungi.computer/agar/agents";
|
|
3
|
+
import { type Handoff } from "@fungi.computer/agar/channels";
|
|
4
|
+
import { type ConversationBinding, type ChannelParty } from "./binding.js";
|
|
5
|
+
export type HandoffEvent = Readonly<{
|
|
6
|
+
expectedVersion: number;
|
|
7
|
+
}> & (Readonly<{
|
|
8
|
+
kind: "request";
|
|
9
|
+
reason: string;
|
|
10
|
+
at: number;
|
|
11
|
+
}> | Readonly<{
|
|
12
|
+
kind: "take_over";
|
|
13
|
+
member: FungiAuthor;
|
|
14
|
+
confirm: boolean;
|
|
15
|
+
at: number;
|
|
16
|
+
}> | Readonly<{
|
|
17
|
+
kind: "hand_back";
|
|
18
|
+
memberId: string;
|
|
19
|
+
confirm: boolean;
|
|
20
|
+
}> | Readonly<{
|
|
21
|
+
kind: "dismiss";
|
|
22
|
+
}>);
|
|
23
|
+
export type HandoffTransition = Readonly<{
|
|
24
|
+
kind: "ok";
|
|
25
|
+
handoff: Handoff;
|
|
26
|
+
}> | Readonly<{
|
|
27
|
+
kind: "conflict" | "confirmation_required" | "not_holder" | "not_found";
|
|
28
|
+
}>;
|
|
29
|
+
/** Decide one handoff; persistence, notifications and cancellation stay with the owner. */
|
|
30
|
+
export declare function transitionHandoff(current: Handoff | null, event: HandoffEvent): HandoffTransition;
|
|
31
|
+
export type ConversationSql = Readonly<{
|
|
32
|
+
exec: (statement: string, ...bindings: (ArrayBuffer | string | number | null)[]) => Readonly<{
|
|
33
|
+
toArray: () => readonly unknown[];
|
|
34
|
+
}>;
|
|
35
|
+
}>;
|
|
36
|
+
/** One verified inbound event from a provider edge. */
|
|
37
|
+
declare const inboundEventSchema: z.ZodObject<{
|
|
38
|
+
bindingId: z.ZodString;
|
|
39
|
+
conversation: z.ZodString;
|
|
40
|
+
eventId: z.ZodString;
|
|
41
|
+
party: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
42
|
+
kind: z.ZodLiteral<"visitor">;
|
|
43
|
+
visitorId: z.ZodString;
|
|
44
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
45
|
+
kind: z.ZodLiteral<"discord-user">;
|
|
46
|
+
guildId: z.ZodString;
|
|
47
|
+
userId: z.ZodString;
|
|
48
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
49
|
+
kind: z.ZodLiteral<"email-sender">;
|
|
50
|
+
address: z.ZodEmail;
|
|
51
|
+
dmarc: z.ZodEnum<{
|
|
52
|
+
none: "none";
|
|
53
|
+
pass: "pass";
|
|
54
|
+
fail: "fail";
|
|
55
|
+
}>;
|
|
56
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
57
|
+
kind: z.ZodLiteral<"player">;
|
|
58
|
+
worldId: z.ZodString;
|
|
59
|
+
playerId: z.ZodString;
|
|
60
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
61
|
+
kind: z.ZodLiteral<"source">;
|
|
62
|
+
source: z.ZodString;
|
|
63
|
+
}, z.core.$strict>], "kind">;
|
|
64
|
+
text: z.ZodString;
|
|
65
|
+
sourceRequestId: z.ZodOptional<z.ZodLazy<z.ZodString>>;
|
|
66
|
+
bodyDigest: z.ZodOptional<z.ZodString>;
|
|
67
|
+
}, z.core.$strict>;
|
|
68
|
+
/** One verified inbound event. */
|
|
69
|
+
export type InboundEvent = z.infer<typeof inboundEventSchema>;
|
|
70
|
+
/** Channel events and composer requests do not share the Session owner's key space. */
|
|
71
|
+
export declare function channelRequestId(bindingId: string, eventId: string): string;
|
|
72
|
+
/** Closed intake result; "said no" is distinct from "couldn't answer". */
|
|
73
|
+
export type IntakeResult = Readonly<{
|
|
74
|
+
kind: "accepted";
|
|
75
|
+
sessionId: string;
|
|
76
|
+
commandId: string;
|
|
77
|
+
delivery: "new" | "replay";
|
|
78
|
+
}> | Readonly<{
|
|
79
|
+
/** Held for a person: recorded as a party line, no run started. */
|
|
80
|
+
kind: "held";
|
|
81
|
+
sessionId: string;
|
|
82
|
+
delivery: "new" | "replay";
|
|
83
|
+
}> | Readonly<{
|
|
84
|
+
kind: "denied";
|
|
85
|
+
reason: "unmapped" | "suspended" | "banned" | "too_long" | "party_daily_limit" | "new_party_limit" | "rate_limited" | "event_conflict";
|
|
86
|
+
}>;
|
|
87
|
+
/** One channel conversation row, as owner surfaces label it. */
|
|
88
|
+
export type ChannelConversation = Readonly<{
|
|
89
|
+
bindingId: string;
|
|
90
|
+
conversation: string;
|
|
91
|
+
sessionId: string;
|
|
92
|
+
party: ChannelParty;
|
|
93
|
+
label: string;
|
|
94
|
+
createdAt: number;
|
|
95
|
+
lastEventAt: number;
|
|
96
|
+
handoff: Handoff;
|
|
97
|
+
}>;
|
|
98
|
+
export type ChannelHandoffResult = Readonly<{
|
|
99
|
+
kind: "ok";
|
|
100
|
+
conversation: ChannelConversation;
|
|
101
|
+
}> | Exclude<HandoffTransition, {
|
|
102
|
+
kind: "ok";
|
|
103
|
+
}>;
|
|
104
|
+
type ChannelTakeoverReceipt = Readonly<{
|
|
105
|
+
version: number;
|
|
106
|
+
memberId: string;
|
|
107
|
+
memberName: string;
|
|
108
|
+
previousMemberId: string | null;
|
|
109
|
+
at: number;
|
|
110
|
+
}>;
|
|
111
|
+
/** Payload-free event metadata for a Team member's channel log. */
|
|
112
|
+
export type ChannelEventReceipt = Readonly<{
|
|
113
|
+
eventId: string;
|
|
114
|
+
receivedAt: number;
|
|
115
|
+
status: "pending" | "accepted" | "held";
|
|
116
|
+
size: number;
|
|
117
|
+
sessionId: string;
|
|
118
|
+
}>;
|
|
119
|
+
/** Only the withdrawal outcomes a channel visitor can observe. */
|
|
120
|
+
export type ChannelWithdrawResult = Readonly<{
|
|
121
|
+
status: "unknown";
|
|
122
|
+
}> | Readonly<{
|
|
123
|
+
status: "accepted";
|
|
124
|
+
commandId: string;
|
|
125
|
+
sessionId?: string;
|
|
126
|
+
}>;
|
|
127
|
+
/** Only the pending fields a channel visitor can read. */
|
|
128
|
+
export type ChannelPendingPrompt = Readonly<{
|
|
129
|
+
requestId: string;
|
|
130
|
+
commandId: string;
|
|
131
|
+
text: string;
|
|
132
|
+
meta?: MessageMetaValue | undefined;
|
|
133
|
+
delivery: "steer" | "followUp";
|
|
134
|
+
images?: readonly Readonly<{
|
|
135
|
+
type: "image";
|
|
136
|
+
data: string;
|
|
137
|
+
mimeType: string;
|
|
138
|
+
}>[] | undefined;
|
|
139
|
+
}>;
|
|
140
|
+
/** The channel's narrow Session port; hosts translate to their durable client. */
|
|
141
|
+
export type SessionDoor = Readonly<{
|
|
142
|
+
withdraw: (sessionId: string, requestId: string) => Promise<ChannelWithdrawResult>;
|
|
143
|
+
latestPending: (sessionId: string, visitor: FungiAuthor) => Promise<ChannelPendingPrompt | null>;
|
|
144
|
+
createSession: (requestId: string) => Promise<string>;
|
|
145
|
+
/** Deliver this conversation Session's tool grants to the runtime. */
|
|
146
|
+
deliverGrants: (sessionId: string) => void;
|
|
147
|
+
prompt: (sessionId: string, input: Readonly<{
|
|
148
|
+
requestId: string;
|
|
149
|
+
text: string;
|
|
150
|
+
meta: AuthorMeta & Readonly<{
|
|
151
|
+
sourceRequestId?: string;
|
|
152
|
+
}>;
|
|
153
|
+
}>) => Promise<Readonly<{
|
|
154
|
+
commandId: string;
|
|
155
|
+
}>>;
|
|
156
|
+
/** Record one run-free operator or party line (Shiitake `operator`). */
|
|
157
|
+
line: (sessionId: string, input: Readonly<{
|
|
158
|
+
requestId: string;
|
|
159
|
+
text: string;
|
|
160
|
+
}> & (Readonly<{
|
|
161
|
+
author: "operator";
|
|
162
|
+
identity: FungiAuthor;
|
|
163
|
+
}> | Readonly<{
|
|
164
|
+
author: "party";
|
|
165
|
+
meta: AuthorMeta & Readonly<{
|
|
166
|
+
sourceRequestId?: string;
|
|
167
|
+
}>;
|
|
168
|
+
}>)) => Promise<void>;
|
|
169
|
+
/** Only a matching, contract-closed request clears a visitor reservation. */
|
|
170
|
+
errorKind: (error: Error, requestId: string) => "closed_request" | null;
|
|
171
|
+
}>;
|
|
172
|
+
export declare function createChannelConversations(options: Readonly<{
|
|
173
|
+
sql: ConversationSql;
|
|
174
|
+
transactionSync: <T>(body: () => T) => T;
|
|
175
|
+
binding: (bindingId: string) => ConversationBinding | null;
|
|
176
|
+
door: Pick<SessionDoor, "createSession" | "deliverGrants" | "prompt" | "line" | "errorKind">;
|
|
177
|
+
now: () => number;
|
|
178
|
+
/** Commit hook for accepted work, in the acceptance transaction. */
|
|
179
|
+
onAccepted?: (accepted: Readonly<{
|
|
180
|
+
binding: ConversationBinding;
|
|
181
|
+
event: InboundEvent;
|
|
182
|
+
sessionId: string;
|
|
183
|
+
commandId: string;
|
|
184
|
+
}>) => void;
|
|
185
|
+
}>): {
|
|
186
|
+
ensure: () => void;
|
|
187
|
+
open: (binding: ConversationBinding, conversation: string, party: ChannelParty) => Promise<Readonly<{
|
|
188
|
+
kind: "open";
|
|
189
|
+
conversation: ChannelConversation;
|
|
190
|
+
}> | Readonly<{
|
|
191
|
+
kind: "denied";
|
|
192
|
+
reason: "new_party_limit" | "banned";
|
|
193
|
+
}>>;
|
|
194
|
+
receive: (rawEvent: InboundEvent) => Promise<IntakeResult>;
|
|
195
|
+
/** A visitor bearer may never resolve another conversation's intake key. */
|
|
196
|
+
visitorEventConflict: (bindingId: string, visitorId: string, eventId: string) => boolean;
|
|
197
|
+
ban: (bindingId: string, conversation: string) => void;
|
|
198
|
+
list: (bindingId?: string) => readonly ChannelConversation[];
|
|
199
|
+
recentEvents: (bindingId: string) => readonly ChannelEventReceipt[];
|
|
200
|
+
requestHandoff: (sessionId: string, reason: string) => ChannelHandoffResult;
|
|
201
|
+
captureTurn: (sessionId: string, commandId: string) => void;
|
|
202
|
+
turnIsCurrent: (sessionId: string, commandId: string) => boolean;
|
|
203
|
+
deliverAgentReply: (sessionId: string, commandId: string, reply: Readonly<{
|
|
204
|
+
kind: "message";
|
|
205
|
+
messageId: string;
|
|
206
|
+
}> | Readonly<{
|
|
207
|
+
kind: "settlement";
|
|
208
|
+
}>) => boolean;
|
|
209
|
+
dueNotifications: (now: number) => readonly ChannelConversation[];
|
|
210
|
+
nextNotification: () => number | null;
|
|
211
|
+
scheduleNotification: (sessionId: string, dueAt: number | null) => void;
|
|
212
|
+
handoffOpen: (sessionId: string, version: number) => boolean;
|
|
213
|
+
takeOver: (sessionId: string, member: FungiAuthor, expectedVersion: number, confirm: boolean) => ChannelHandoffResult;
|
|
214
|
+
handBack: (sessionId: string, memberId: string, expectedVersion: number, confirm: boolean) => ChannelHandoffResult;
|
|
215
|
+
dismiss: (sessionId: string, expectedVersion: number) => ChannelHandoffResult;
|
|
216
|
+
takeovers: (sessionId: string) => readonly ChannelTakeoverReceipt[];
|
|
217
|
+
expired: (now: number, retentionMs: (bindingId: string) => number) => readonly ChannelConversation[];
|
|
218
|
+
nextExpiry: (retentionMs: (bindingId: string) => number) => number | null;
|
|
219
|
+
forget: (conversation: ChannelConversation) => void;
|
|
220
|
+
find: (bindingId: string, conversation: string) => Readonly<{
|
|
221
|
+
bindingId: string;
|
|
222
|
+
conversation: string;
|
|
223
|
+
sessionId: string;
|
|
224
|
+
party: ChannelParty;
|
|
225
|
+
label: string;
|
|
226
|
+
createdAt: number;
|
|
227
|
+
lastEventAt: number;
|
|
228
|
+
handoff: Handoff;
|
|
229
|
+
}> | null;
|
|
230
|
+
sessionConversation: (sessionId: string) => ChannelConversation | null;
|
|
231
|
+
sessionIds: () => readonly string[];
|
|
232
|
+
};
|
|
233
|
+
/** AgentDO's channel conversation owner. */
|
|
234
|
+
export type ChannelConversations = ReturnType<typeof createChannelConversations>;
|
|
235
|
+
export {};
|