@finalai/final-agent-provider 0.7.0 → 0.9.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.
Files changed (76) hide show
  1. package/HOSTING.md +3 -3
  2. package/README.md +26 -91
  3. package/dist/modules/channel-factories.d.mts +5 -6
  4. package/dist/modules/channel-factories.mjs +7 -11
  5. package/dist/modules/channel-factories.mjs.map +3 -3
  6. package/dist/modules/channels/inbound.mjs +2 -2
  7. package/dist/modules/channels/inbound.mjs.map +2 -2
  8. package/dist/modules/channels/index.d.mts +0 -7
  9. package/dist/modules/channels/index.mjs +0 -7
  10. package/dist/modules/channels/index.mjs.map +2 -2
  11. package/dist/modules/channels/prompt.d.mts +2 -2
  12. package/dist/modules/channels/prompt.mjs +3 -3
  13. package/dist/modules/channels/prompt.mjs.map +2 -2
  14. package/dist/modules/channels/routing.d.mts +1 -1
  15. package/dist/modules/channels/routing.mjs +1 -1
  16. package/dist/modules/channels/routing.mjs.map +1 -1
  17. package/dist/modules/sandboxes/bytes.d.mts +1 -0
  18. package/dist/modules/sandboxes/bytes.mjs +7 -1
  19. package/dist/modules/sandboxes/bytes.mjs.map +2 -2
  20. package/dist/modules/sandboxes/computer-processes.mjs +5 -3
  21. package/dist/modules/sandboxes/computer-processes.mjs.map +2 -2
  22. package/dist/modules/sandboxes/computer.mjs +5 -1
  23. package/dist/modules/sandboxes/computer.mjs.map +2 -2
  24. package/dist/modules/sandboxes/computers-api-transport.d.mts +1 -1
  25. package/dist/modules/sandboxes/computers-api-transport.mjs +8 -0
  26. package/dist/modules/sandboxes/computers-api-transport.mjs.map +2 -2
  27. package/dist/modules/sandboxes/device-api.mjs +8 -0
  28. package/dist/modules/sandboxes/device-api.mjs.map +2 -2
  29. package/dist/modules/sandboxes/device.mjs +6 -0
  30. package/dist/modules/sandboxes/device.mjs.map +2 -2
  31. package/dist/modules/sandboxes/session.d.mts +1 -0
  32. package/dist/modules/sandboxes/session.mjs +106 -36
  33. package/dist/modules/sandboxes/session.mjs.map +3 -3
  34. package/dist/modules/sandboxes/testing/conformance.mjs +3 -0
  35. package/dist/modules/sandboxes/testing/conformance.mjs.map +2 -2
  36. package/dist/modules/sandboxes/testing/fake-machine.mjs +11 -0
  37. package/dist/modules/sandboxes/testing/fake-machine.mjs.map +2 -2
  38. package/dist/modules/sandboxes/transport.d.mts +1 -0
  39. package/dist/modules/sandboxes/transport.mjs.map +2 -2
  40. package/package.json +4 -40
  41. package/dist/modules/channels/channel-utils.d.mts +0 -132
  42. package/dist/modules/channels/channel-utils.mjs +0 -445
  43. package/dist/modules/channels/channel-utils.mjs.map +0 -7
  44. package/dist/modules/channels/discord-dispatch.d.mts +0 -17
  45. package/dist/modules/channels/discord-dispatch.mjs +0 -139
  46. package/dist/modules/channels/discord-dispatch.mjs.map +0 -7
  47. package/dist/modules/channels/discord-gateway.d.mts +0 -19
  48. package/dist/modules/channels/discord-gateway.mjs +0 -233
  49. package/dist/modules/channels/discord-gateway.mjs.map +0 -7
  50. package/dist/modules/channels/discord.d.mts +0 -9
  51. package/dist/modules/channels/discord.mjs +0 -904
  52. package/dist/modules/channels/discord.mjs.map +0 -7
  53. package/dist/modules/channels/github.d.mts +0 -5
  54. package/dist/modules/channels/github.mjs +0 -720
  55. package/dist/modules/channels/github.mjs.map +0 -7
  56. package/dist/modules/channels/linear.d.mts +0 -4
  57. package/dist/modules/channels/linear.mjs +0 -621
  58. package/dist/modules/channels/linear.mjs.map +0 -7
  59. package/dist/modules/channels/phone.d.mts +0 -8
  60. package/dist/modules/channels/phone.mjs +0 -382
  61. package/dist/modules/channels/phone.mjs.map +0 -7
  62. package/dist/modules/channels/reply-receipts.d.mts +0 -31
  63. package/dist/modules/channels/reply-receipts.mjs +0 -63
  64. package/dist/modules/channels/reply-receipts.mjs.map +0 -7
  65. package/dist/modules/channels/slack.d.mts +0 -7
  66. package/dist/modules/channels/slack.mjs +0 -1134
  67. package/dist/modules/channels/slack.mjs.map +0 -7
  68. package/dist/modules/channels/voice-recording.d.mts +0 -7
  69. package/dist/modules/channels/voice-recording.mjs +0 -49
  70. package/dist/modules/channels/voice-recording.mjs.map +0 -7
  71. package/dist/modules/channels/voice.d.mts +0 -33
  72. package/dist/modules/channels/voice.mjs +0 -851
  73. package/dist/modules/channels/voice.mjs.map +0 -7
  74. package/dist/modules/channels/webhook.d.mts +0 -5
  75. package/dist/modules/channels/webhook.mjs +0 -76
  76. package/dist/modules/channels/webhook.mjs.map +0 -7
package/HOSTING.md CHANGED
@@ -269,6 +269,6 @@ Optional readers preserve source compatibility with existing hosts. Definitions
269
269
  requesting bindings fail clearly if hosting does not provide them. Installing these
270
270
  packages alone does not change Final's deployed service wiring or provision secrets.
271
271
 
272
- New compiles emit manifest version 4. Hosts and stored revisions must use v4;
273
- recompile older definitions before loading them. Upgrade hosting before
274
- publishing newly compiled agents.
272
+ New compiles emit manifest version 4. Hosts read versions 2 through 4; older
273
+ channel entries default to no credentials and an empty surface. Upgrade hosting
274
+ before publishing newly compiled agents.
package/README.md CHANGED
@@ -31,6 +31,25 @@ The `modelZod(ids)` and `modelJson(ids, defaultId)` helpers retain explicit rest
31
31
 
32
32
  SDK 0.2.0 removes `@finalai/agents/models` and `@finalai/final-agent-provider/harnesses/models`, including their model arrays, defaults, model-ID unions and pricing helpers. Use string model references and the installed platform’s harness description for current candidates and defaults. Pricing belongs to the hosting platform. The protocol-level `ModelVendor` enum remains available from `@finalai/final-agent-provider/harnesses`.
33
33
 
34
+ ## Durable processes
35
+
36
+ The `computer` and `device` sandboxes offer durable processes
37
+ (`SandboxCapability.DurableProcesses`: `spawn({ durable: true })` and `attachProcess`) on
38
+ write and execute bindings. A ref names the sandbox, the process and its boot (and, on a
39
+ Device, the lease generation), so a ref from another sandbox, boot or generation attaches
40
+ to nothing. A dropped handle stops polling and never terminates the process; `timeoutMs`
41
+ is enforced by the computer or Device itself.
42
+
43
+ - Computers: managed processes run in the computer and are found by id and boot until it
44
+ boots again (a pause and resume keeps them; a stop, or a wake that boots it, does not)
45
+ or is deleted. The guest keeps only the first 8 MiB of each stream; later output is
46
+ not retained.
47
+ - Devices: lease processes end with the lease generation (released, expired or
48
+ superseded); attaching afterwards returns null. The Device keeps the most recent 1 MiB
49
+ of each stream, so an attached stream may start later than asked (`stdoutOffset` and
50
+ `stderrOffset` say where). A process whose output was read to the end after it exited
51
+ may be retired, and then attaches to nothing.
52
+
34
53
  ## Workspace Device egress
35
54
 
36
55
  `/sandboxes/egress` supplies provider-neutral Linux TCP/UDP/DNS routing through approved Final Devices. Hosts compose `createWorkspaceDeviceNetworking({ api, needed })` through the generic provider `networking` option. They supply stable logical workspace identity, durable networking registration, the current actor, and the raw privileged sandbox session. Preserve the direct policy before boot fencing; restore it on Disable. Configure and Disable ask for consent by default.
@@ -42,94 +61,10 @@ a networking extension. Use ordinary resume for execution. The bundled adapters
42
61
  cache deferred setup failures per handle; reconnect to retry rather than replaying
43
62
  partially completed user setup commands on each MCP poll.
44
63
 
45
- ## Provider channels
46
-
47
- Use the same provider package with your own app or a shared installation:
48
-
49
- ```ts
50
- import { slackChannel } from '@finalai/final-agent-provider/channels/slack';
51
- export default slackChannel();
52
- ```
53
-
54
- Factories also exist for Discord, GitHub, Linear, authenticated webhooks, voice,
55
- and Twilio phone calls. Slack uses a separate OpenID identity flow; Linear uses
56
- `actor=user` for identity proof and `actor=app` for application installation.
57
- Provider principals are never matched by email. Slack Enterprise Grid principals
58
- use the enterprise user/enterprise namespace when available.
59
-
60
- Slack installs are scoped to a workspace, including workspaces in Enterprise Grid. Organization-wide installs with no workspace claim are rejected; install the app in each workspace that should connect. Discord guilds share the installed application bot token. Slack group direct messages are not subscribed; use a direct message or mention the app in a workspace channel.
61
-
62
- Slack and Discord default to `history: 'none'`. Opt into `linked-members` to send
63
- only currently linked members' thread history to the agent. Shared places default
64
- to member-only input and origin-only replies. Configure `replies: all` explicitly
65
- to mirror the chat. Provider signature verification is required on `/webhook`;
66
- Discord also maintains a Gateway listener without the privileged message-content
67
- intent. Requests must still fit the provider application's installed scopes.
68
-
69
- `webhookChannel({secret})` verifies `X-Final-Signature: sha256=<HMAC hex>` over the
70
- raw body. Its envelope is `{place,label,content,idempotencyKey,context?}`. Connect
71
- its place before delivering events. Retries reuse the event's idempotency key.
72
-
73
- `voiceChannel()` verifies a Final OAuth identity with PKCE, then serves `/stream`.
74
- A JSON `start` frame selects PCM16 at 16 kHz and the authenticated principal;
75
- binary frames carry microphone samples. `cancel` interrupts a turn and `stop`
76
- finishes input while output drains. Only `speech.end` with `final: true` marks
77
- the drained terminal response; per-turn ends use `final: false`. Server frames report transcripts, speech
78
- boundaries, stage timestamps and errors, interleaved with binary PCM output.
79
- An `error` with `recoverable: true` is advisory; other error frames are terminal.
80
- A `notice` ends microphone capture while its spoken explanation drains. Stop
81
- sending audio, display the notice and continue playback until the terminal
82
- `speech.end`, including when the server ends the call without a client `stop`.
83
- Only final utterances are posted. Once-only permission choices and empty-schema
84
- confirmations can be answered by voice; other forms remain in Final. When recording is enabled, the channel attaches recordings without starting another turn.
85
- Clients opt in to recording in the start frame after displaying the recording notice.
86
- Saved recordings are PCM16 WAV attachments, split below 10 MiB including base64 serialization.
87
-
88
- `phoneChannel({accountSid,fromNumber})` adapts the same core to signed Twilio call
89
- webhooks and 8 kHz mu-law streams. It uses the declared `twilio-auth-token` secret
90
- and an SMS challenge for identity. An unlinked member caller receives the account-link
91
- URL by SMS, signs in and verifies their number, then calls again. Each linked call also requires a fresh SMS code
92
- entered on the call; caller ID alone cannot act as a member. Configure `audience:'anyone'` explicitly for
93
- anonymous support calls; those calls use captioned input and group defaults.
94
-
95
- Provider delivery receipts expire after 90 days; later provider edits may no longer find their original delivery.
96
- Provider mutation support varies: Slack, Discord and GitHub update bot-owned
97
- replies. Linear activities are emitted as separate entries and are not edited by
98
- this adapter. GitHub has no inbound reaction
99
- webhook. Final room customization remains `finalChannel` from `/channels/final`.
100
-
101
- Slack direct-message replies stay in a thread under the original request, so each
102
- reply, edit and reaction remains associated with its source message. Approvals
103
- show the requested action and the provider's one-time option names. Ambiguous
104
- spoken answers and decisions that require a form must be answered in Final;
105
- channels do not offer permanent approval choices.
106
-
107
- Slack Grid workspace removals revoke that workspace's routes and identities. An
108
- enterprise identity remains linked while another workspace has successfully
109
- proven an active grant. Tracking is bounded to 256 workspaces per enterprise;
110
- overflow conservatively requires enterprise identities to link again after the
111
- next workspace removal. Phone verification requests use a per-number cooldown.
112
-
113
- Configure Slack's `/final` slash command and interactivity callback in your app
114
- settings. Register Discord's `/final` application command with `connect`,
115
- `disconnect` and `unlink` subcommands. The SDK handles dispatched commands and
116
- keeps your application's command registry under your control.
117
-
118
- `replies: all` mirrors new messages. Slack, Discord, and GitHub can edit or remove
119
- existing copies and synchronize supported reactions while their delivery receipts
120
- are retained. Missing or deleted copies are not recreated by later mutations.
121
- Apps can modify only messages they own. The Linear adapter does not propagate
122
- Final edits, removals, or reactions to its activity entries. Provider permissions
123
- and receipt retention limit later synchronization.
124
-
125
- Hosts that terminate TLS upstream must give channel routes the public request URL,
126
- including its scheme; Twilio verifies the complete URL. Voice closes a connection
127
- if pending microphone audio exceeds 2 MiB instead of retaining an unbounded queue.
128
- Discord guild removal ends that guild's connections while preserving identity
129
- proofs usable in other guilds or direct messages.
130
-
131
- Discord guild history is limited to content the bot can read without privileged
132
- message-content access, such as mentions; unavailable content is omitted. GitHub
133
- installation suspension pauses incoming delivery without deleting connections;
134
- unsuspending resumes it. Voice synthesizes text replies through the configured
135
- speech service; audio attachments remain available in Final.
64
+ ## Authored channels
65
+
66
+ External integrations are ordinary authored modules built with `defineChannel`
67
+ from `@finalai/agent-provider`. The SDK provides scoped platform capabilities and
68
+ opaque credential operations; application implementations live with their source.
69
+ Final chat customization uses `finalChannel` from `/channels/final` and is compiled
70
+ into the authored bundle in the same way as other customization code.
@@ -1,14 +1,13 @@
1
1
  import type { SessionUpdate } from '@agentclientprotocol/sdk/experimental/v2';
2
- import { TurnPolicy, type ChannelAuthIface, type RoomSurfaceDefinitionIface, type ChannelInputResponseIface, type ChannelMessageCompletedDataIface, type ChannelMessageDeltaDataIface, type RoomReceiveContextIface, type ChannelTurnEventDataIface, type ChannelTurnStateIface, type ConversationMessageIface, type DecisionCreatedDataIface, type DecisionResolvedDataIface, type JsonValue } from '@finalai/agent-provider';
3
- export declare const FINAL_CHANNEL_SPECIFIER = "@finalai/final-agent-provider/channels/final";
4
- export { ChannelPrincipalType, type ChannelAuthIface } from '@finalai/agent-provider';
2
+ import { TurnPolicy, type RoomAuthIface, type RoomSurfaceDefinitionIface, type RoomInputResponseIface, type ChannelMessageCompletedDataIface, type ChannelMessageDeltaDataIface, type RoomReceiveContextIface, type ChannelTurnEventDataIface, type ChannelTurnStateIface, type ConversationMessageIface, type DecisionCreatedDataIface, type DecisionResolvedDataIface, type JsonValue } from '@finalai/agent-provider';
3
+ export { RoomPrincipalType, type RoomAuthIface } from '@finalai/agent-provider';
5
4
  export interface ChannelAdmissionIface {
6
- auth: ChannelAuthIface | null;
5
+ auth: RoomAuthIface | null;
7
6
  context?: string[];
8
7
  title?: string;
9
8
  }
10
9
  export interface FinalMessageContextIface extends RoomReceiveContextIface {
11
- defaultAuth: ChannelAuthIface | null;
10
+ defaultAuth: RoomAuthIface | null;
12
11
  }
13
12
  export interface FinalChannelContextIface {
14
13
  final: {
@@ -34,7 +33,7 @@ export interface FinalChannelOptionsIface {
34
33
  updateIntervalMs?: number;
35
34
  route?: RoomSurfaceDefinitionIface<JsonValue, JsonValue>['route'];
36
35
  onMessage?: (ctx: FinalMessageContextIface, message: ConversationMessageIface) => ChannelAdmissionIface | null | Promise<ChannelAdmissionIface | null>;
37
- onInputResponse?: (ctx: FinalMessageContextIface, response: ChannelInputResponseIface) => ChannelAdmissionIface | null | Promise<ChannelAdmissionIface | null>;
36
+ onInputResponse?: (ctx: FinalMessageContextIface, response: RoomInputResponseIface) => ChannelAdmissionIface | null | Promise<ChannelAdmissionIface | null>;
38
37
  events?: FinalChannelEventHandlersIface;
39
38
  renderer?: (update: SessionUpdate, channel: FinalChannelContextIface, ctx: FinalSessionContextIface, next: () => Promise<void>) => void | Promise<void>;
40
39
  }
@@ -1,23 +1,21 @@
1
1
  import {
2
- ChannelPrincipalType,
2
+ RoomPrincipalType,
3
3
  SemanticChannelEventKind,
4
4
  TurnPolicy,
5
- channelAuthSchema,
5
+ roomAuthSchema,
6
6
  channelMessageCompletedSchema,
7
7
  decisionCreatedDataSchema,
8
8
  decisionResolvedDataSchema,
9
9
  defineRoomSurface,
10
- jsonObjectSchema,
11
- packageRef
10
+ jsonObjectSchema
12
11
  } from "@finalai/agent-provider";
13
12
  import * as z from "zod";
14
13
  import { contentBlocksOf } from "./channels/content.mjs";
15
14
  import { conversationEventInboundSchema, messageInboundSchema } from "./channels/inbound.mjs";
16
15
  import { createMessagingChannel } from "./channels/messaging-channel.mjs";
17
- const FINAL_CHANNEL_SPECIFIER = "@finalai/final-agent-provider/channels/final";
18
- import { ChannelPrincipalType as ChannelPrincipalType2 } from "@finalai/agent-provider";
16
+ import { RoomPrincipalType as RoomPrincipalType2 } from "@finalai/agent-provider";
19
17
  const admissionSchema = z.object({
20
- auth: channelAuthSchema.nullable(),
18
+ auth: roomAuthSchema.nullable(),
21
19
  context: z.array(z.string()).optional(),
22
20
  title: z.string().optional()
23
21
  });
@@ -29,7 +27,7 @@ const defaultAuthOf = (author) => {
29
27
  if (author == null) return null;
30
28
  return {
31
29
  principalId: author.userId ?? author.definitionId ?? author.id,
32
- principalType: author.userId == null ? ChannelPrincipalType.Service : ChannelPrincipalType.User,
30
+ principalType: author.userId == null ? RoomPrincipalType.Service : RoomPrincipalType.User,
33
31
  authenticator: "final",
34
32
  displayName: author.displayName,
35
33
  attributes: { participant_id: author.id }
@@ -163,7 +161,6 @@ const finalChannel = (inputOptions = {}) => {
163
161
  defineRoomSurface({
164
162
  ...base,
165
163
  config: jsonObjectSchema.parse(config),
166
- installed: options.onMessage == null && options.onInputResponse == null && options.events == null && options.renderer == null && options.route == null ? packageRef(FINAL_CHANNEL_SPECIFIER) : void 0,
167
164
  configure: (next) => finalChannel({ ...options, ...optionsSchema.parse({ ...config, ...next }) }),
168
165
  receive,
169
166
  respond: async (input, ctx) => {
@@ -209,8 +206,7 @@ const finalChannel = (inputOptions = {}) => {
209
206
  );
210
207
  };
211
208
  export {
212
- ChannelPrincipalType2 as ChannelPrincipalType,
213
- FINAL_CHANNEL_SPECIFIER,
209
+ RoomPrincipalType2 as RoomPrincipalType,
214
210
  finalChannel
215
211
  };
216
212
  //# sourceMappingURL=channel-factories.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/channel-factories.ts"],
4
- "sourcesContent": ["import type { ContentBlock, SessionUpdate } from '@agentclientprotocol/sdk/experimental/v2';\nimport {\n ChannelPrincipalType,\n SemanticChannelEventKind,\n TurnPolicy,\n channelAuthSchema,\n channelMessageCompletedSchema,\n decisionCreatedDataSchema,\n decisionResolvedDataSchema,\n defineRoomSurface,\n jsonObjectSchema,\n packageRef,\n type ChannelAuthIface,\n type RoomSurfaceDefinitionIface,\n type RoomEventHandler,\n type ChannelInputResponseIface,\n type ChannelMessageCompletedDataIface,\n type ChannelMessageDeltaDataIface,\n type RoomReceiveContextIface,\n type ChannelTurnEventDataIface,\n type ChannelTurnStateIface,\n type ConversationMessageIface,\n type DecisionCreatedDataIface,\n type DecisionResolvedDataIface,\n type JsonValue,\n type ProjectionContextIface,\n} from '@finalai/agent-provider';\nimport * as z from 'zod';\nimport { contentBlocksOf } from \"./channels/content.mjs\";\nimport { conversationEventInboundSchema, messageInboundSchema } from \"./channels/inbound.mjs\";\nimport { createMessagingChannel } from \"./channels/messaging-channel.mjs\";\n\nexport const FINAL_CHANNEL_SPECIFIER = '@finalai/final-agent-provider/channels/final';\n\nexport { ChannelPrincipalType, type ChannelAuthIface } from '@finalai/agent-provider';\n\nexport interface ChannelAdmissionIface {\n auth: ChannelAuthIface | null;\n context?: string[];\n title?: string;\n}\n\nexport interface FinalMessageContextIface extends RoomReceiveContextIface {\n defaultAuth: ChannelAuthIface | null;\n}\n\nexport interface FinalChannelContextIface {\n final: {\n post(message: ChannelMessageCompletedDataIface['message']): Promise<ConversationMessageIface>;\n };\n}\nexport interface FinalSessionContextIface {\n sessionId: string | null;\n turnId: string;\n state: ChannelTurnStateIface<JsonValue>;\n}\nexport type FinalChannelEventHandler<Data> = (\n data: Data,\n channel: FinalChannelContextIface,\n ctx: FinalSessionContextIface,\n) => void | Promise<void>;\nexport interface FinalChannelEventHandlersIface {\n 'message.delta'?: FinalChannelEventHandler<ChannelMessageDeltaDataIface>;\n 'message.completed'?: FinalChannelEventHandler<ChannelMessageCompletedDataIface>;\n 'turn.started'?: FinalChannelEventHandler<ChannelTurnEventDataIface>;\n 'turn.completed'?: FinalChannelEventHandler<ChannelTurnEventDataIface>;\n 'decision.created'?: FinalChannelEventHandler<DecisionCreatedDataIface>;\n 'decision.resolved'?: FinalChannelEventHandler<DecisionResolvedDataIface>;\n}\n\nexport interface FinalChannelOptionsIface {\n turnPolicy?: TurnPolicy | `${TurnPolicy}`;\n updateIntervalMs?: number;\n route?: RoomSurfaceDefinitionIface<JsonValue, JsonValue>['route'];\n onMessage?: (\n ctx: FinalMessageContextIface,\n message: ConversationMessageIface,\n ) => ChannelAdmissionIface | null | Promise<ChannelAdmissionIface | null>;\n onInputResponse?: (\n ctx: FinalMessageContextIface,\n response: ChannelInputResponseIface,\n ) => ChannelAdmissionIface | null | Promise<ChannelAdmissionIface | null>;\n events?: FinalChannelEventHandlersIface;\n renderer?: (\n update: SessionUpdate,\n channel: FinalChannelContextIface,\n ctx: FinalSessionContextIface,\n next: () => Promise<void>,\n ) => void | Promise<void>;\n}\n\nconst admissionSchema = z.object({\n auth: channelAuthSchema.nullable(),\n context: z.array(z.string()).optional(),\n title: z.string().optional(),\n});\n\nconst optionsSchema = z.object({\n turnPolicy: z.nativeEnum(TurnPolicy).default(TurnPolicy.Steer),\n updateIntervalMs: z.number().finite().nonnegative().optional(),\n});\n\n// A room member as a principal: a person by user id, an agent by definition id.\nconst defaultAuthOf = (\n author: import('@finalai/agent-provider').ParticipantIface | undefined,\n): ChannelAuthIface | null => {\n if (author == null) return null;\n return {\n principalId: author.userId ?? author.definitionId ?? author.id,\n principalType: author.userId == null ? ChannelPrincipalType.Service : ChannelPrincipalType.User,\n authenticator: 'final',\n displayName: author.displayName,\n attributes: { participant_id: author.id },\n };\n};\n\nexport const finalChannel = (\n inputOptions: FinalChannelOptionsIface = {},\n): RoomSurfaceDefinitionIface<JsonValue, JsonValue> => {\n const options = {\n ...inputOptions,\n events: inputOptions.events == null ? undefined : { ...inputOptions.events },\n };\n const callbacks = {\n onMessage: options.onMessage,\n onInputResponse: options.onInputResponse,\n renderer: options.renderer,\n route: options.route,\n ...options.events,\n };\n for (const [name, callback] of Object.entries(callbacks))\n if (callback != null && !z.function().safeParse(callback).success)\n throw new Error(`Final channel ${name} must be a function`);\n const supportedEvents = new Set([\n 'message.delta',\n 'message.completed',\n 'turn.started',\n 'turn.completed',\n 'decision.created',\n 'decision.resolved',\n ]);\n for (const kind of Object.keys(options.events ?? {}))\n if (!supportedEvents.has(kind)) throw new Error(`unsupported Final channel event: ${kind}`);\n const config = optionsSchema.parse(options);\n const base = createMessagingChannel({ ...config, route: options.route });\n const receive: typeof base.receive = async (input, ctx) => {\n if (conversationEventInboundSchema.safeParse(input).success) return base.receive(input, ctx);\n const parsed = messageInboundSchema.parse(input);\n const participants =\n ctx.participants ?? (await ctx.platform.conversations.participants(parsed.conversationId));\n const author = participants.find(\n (participant) => participant.id === parsed.authorParticipantId,\n );\n const message =\n ctx.message ??\n (await ctx.platform.conversations.postMessage({\n ...parsed,\n content: contentBlocksOf(parsed.content),\n }));\n if (ctx.definitionId == null) throw new Error('Final channel has no agent definition');\n const messageContext: FinalMessageContextIface = {\n ...ctx,\n defaultAuth: defaultAuthOf(author),\n };\n const accepted =\n options.onMessage == null\n ? { auth: messageContext.defaultAuth }\n : await options.onMessage(messageContext, message);\n const admission = accepted == null ? null : admissionSchema.parse(accepted);\n if (admission == null) return { conversationId: parsed.conversationId };\n const context = admission.context ?? [];\n const injected: ContentBlock[] = context.map((text) => ({ type: 'text', text }));\n return base.receive(\n {\n ...parsed,\n content: [...context.map((text) => ({ type: 'text', text })), ...parsed.content],\n },\n {\n ...ctx,\n platform: {\n ...ctx.platform,\n sessions: {\n ...ctx.platform.sessions,\n prompt: (args) =>\n ctx.platform.sessions.prompt({\n ...args,\n auth: admission.auth,\n title: admission.title,\n }),\n },\n },\n message: { ...message, content: [...injected, ...message.content] },\n },\n );\n };\n const channelContext = (ctx: ProjectionContextIface): FinalChannelContextIface => {\n const { conversation, agentParticipant } = ctx;\n if (conversation == null || agentParticipant == null || agentParticipant.definitionId == null)\n throw new Error('Final platform context requires a Final conversation');\n return {\n final: {\n post: async (message) => {\n if (ctx.platform.conversations.dispatchMessage == null)\n throw new Error('channel dispatch is unavailable');\n const posted = await ctx.platform.conversations.postMessage({\n conversationId: conversation.conversationId,\n authorParticipantId: agentParticipant.id,\n content: contentBlocksOf(message.content),\n clientMessageId: `channel:${ctx.turn.id}:${message.id}`,\n originTurnId: ctx.turn.id,\n });\n await ctx.platform.conversations.dispatchMessage({\n conversationId: posted.conversationId,\n messageId: posted.messageId,\n });\n return posted;\n },\n },\n };\n };\n const sessionContext = (ctx: ProjectionContextIface): FinalSessionContextIface => ({\n sessionId: ctx.sessionId ?? null,\n turnId: ctx.turn.id,\n state: ctx.state,\n });\n const wrap = <Data>(\n schema: z.ZodType<Data>,\n handler: FinalChannelEventHandler<Data> | undefined,\n ): RoomEventHandler | undefined =>\n handler == null\n ? undefined\n : async (event, ctx) =>\n handler(schema.parse(event.data), channelContext(ctx), sessionContext(ctx));\n const authoredEvents = {\n [SemanticChannelEventKind.MessageCompleted]: wrap(\n channelMessageCompletedSchema,\n options.events?.['message.completed'],\n ),\n [SemanticChannelEventKind.MessageDelta]: wrap(\n z.object({ messageId: z.string(), delta: jsonObjectSchema }),\n options.events?.['message.delta'],\n ),\n [SemanticChannelEventKind.TurnStarted]: wrap(\n z.object({ turnId: z.string() }),\n options.events?.['turn.started'],\n ),\n [SemanticChannelEventKind.TurnCompleted]: wrap(\n z.object({ turnId: z.string(), stopReason: z.string().nullable() }),\n options.events?.['turn.completed'],\n ),\n 'decision.created': wrap(decisionCreatedDataSchema, options.events?.['decision.created']),\n 'decision.resolved': wrap(decisionResolvedDataSchema, options.events?.['decision.resolved']),\n };\n const events = { ...base.events };\n for (const [kind, handler] of Object.entries(authoredEvents))\n if (handler != null) events[kind] = handler;\n return Object.freeze(\n defineRoomSurface({\n ...base,\n config: jsonObjectSchema.parse(config),\n installed:\n options.onMessage == null &&\n options.onInputResponse == null &&\n options.events == null &&\n options.renderer == null &&\n options.route == null\n ? packageRef(FINAL_CHANNEL_SPECIFIER)\n : undefined,\n configure: (next) =>\n finalChannel({ ...options, ...optionsSchema.parse({ ...config, ...next }) }),\n receive,\n respond: async (input, ctx) => {\n const conversation = z.string().min(1).parse(ctx.conversationId);\n const participants = await ctx.platform.conversations.participants(conversation);\n const author = participants.find(\n (participant) => participant.id === input.actorParticipantId,\n );\n const defaultAuth = defaultAuthOf(author);\n let admission: ChannelAdmissionIface = { auth: defaultAuth };\n if (options.onInputResponse != null) {\n const accepted = await options.onInputResponse({ ...ctx, defaultAuth }, input);\n if (accepted == null) return { resolved: false };\n admission = admissionSchema.parse(accepted);\n }\n if (ctx.platform.sessions.respond == null)\n throw new Error('response submission is unavailable');\n return ctx.platform.sessions.respond({ ...input, auth: admission.auth });\n },\n cancel: async (ctx) => {\n if (ctx.agentParticipantId == null) return { accepted: false };\n const conversation = z.string().min(1).parse(ctx.conversationId);\n const participants = await ctx.platform.conversations.participants(conversation);\n const agent = participants.find((participant) => participant.id === ctx.agentParticipantId);\n if (agent?.sessionId == null) return { accepted: false };\n await ctx.platform.sessions.cancel({\n participantId: agent.id,\n reason: ctx.cancelReason,\n throughMessageSeq: ctx.cancelThroughMessageSeq,\n });\n return { accepted: true };\n },\n project: async (update, ctx) => {\n const next = () =>\n options.events?.['message.completed'] == null\n ? base.project(update, ctx)\n : Promise.resolve();\n if (options.renderer != null) {\n await options.renderer(update, channelContext(ctx), sessionContext(ctx), next);\n return;\n }\n await next();\n },\n events: Object.freeze(events),\n }),\n );\n};\n"],
5
- "mappings": "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",
6
- "names": ["ChannelPrincipalType"]
4
+ "sourcesContent": ["import type { ContentBlock, SessionUpdate } from '@agentclientprotocol/sdk/experimental/v2';\nimport {\n RoomPrincipalType,\n SemanticChannelEventKind,\n TurnPolicy,\n roomAuthSchema,\n channelMessageCompletedSchema,\n decisionCreatedDataSchema,\n decisionResolvedDataSchema,\n defineRoomSurface,\n jsonObjectSchema,\n type RoomAuthIface,\n type RoomSurfaceDefinitionIface,\n type RoomEventHandler,\n type RoomInputResponseIface,\n type ChannelMessageCompletedDataIface,\n type ChannelMessageDeltaDataIface,\n type RoomReceiveContextIface,\n type ChannelTurnEventDataIface,\n type ChannelTurnStateIface,\n type ConversationMessageIface,\n type DecisionCreatedDataIface,\n type DecisionResolvedDataIface,\n type JsonValue,\n type ProjectionContextIface,\n} from '@finalai/agent-provider';\nimport * as z from 'zod';\nimport { contentBlocksOf } from \"./channels/content.mjs\";\nimport { conversationEventInboundSchema, messageInboundSchema } from \"./channels/inbound.mjs\";\nimport { createMessagingChannel } from \"./channels/messaging-channel.mjs\";\n\nexport { RoomPrincipalType, type RoomAuthIface } from '@finalai/agent-provider';\n\nexport interface ChannelAdmissionIface {\n auth: RoomAuthIface | null;\n context?: string[];\n title?: string;\n}\n\nexport interface FinalMessageContextIface extends RoomReceiveContextIface {\n defaultAuth: RoomAuthIface | null;\n}\n\nexport interface FinalChannelContextIface {\n final: {\n post(message: ChannelMessageCompletedDataIface['message']): Promise<ConversationMessageIface>;\n };\n}\nexport interface FinalSessionContextIface {\n sessionId: string | null;\n turnId: string;\n state: ChannelTurnStateIface<JsonValue>;\n}\nexport type FinalChannelEventHandler<Data> = (\n data: Data,\n channel: FinalChannelContextIface,\n ctx: FinalSessionContextIface,\n) => void | Promise<void>;\nexport interface FinalChannelEventHandlersIface {\n 'message.delta'?: FinalChannelEventHandler<ChannelMessageDeltaDataIface>;\n 'message.completed'?: FinalChannelEventHandler<ChannelMessageCompletedDataIface>;\n 'turn.started'?: FinalChannelEventHandler<ChannelTurnEventDataIface>;\n 'turn.completed'?: FinalChannelEventHandler<ChannelTurnEventDataIface>;\n 'decision.created'?: FinalChannelEventHandler<DecisionCreatedDataIface>;\n 'decision.resolved'?: FinalChannelEventHandler<DecisionResolvedDataIface>;\n}\n\nexport interface FinalChannelOptionsIface {\n turnPolicy?: TurnPolicy | `${TurnPolicy}`;\n updateIntervalMs?: number;\n route?: RoomSurfaceDefinitionIface<JsonValue, JsonValue>['route'];\n onMessage?: (\n ctx: FinalMessageContextIface,\n message: ConversationMessageIface,\n ) => ChannelAdmissionIface | null | Promise<ChannelAdmissionIface | null>;\n onInputResponse?: (\n ctx: FinalMessageContextIface,\n response: RoomInputResponseIface,\n ) => ChannelAdmissionIface | null | Promise<ChannelAdmissionIface | null>;\n events?: FinalChannelEventHandlersIface;\n renderer?: (\n update: SessionUpdate,\n channel: FinalChannelContextIface,\n ctx: FinalSessionContextIface,\n next: () => Promise<void>,\n ) => void | Promise<void>;\n}\n\nconst admissionSchema = z.object({\n auth: roomAuthSchema.nullable(),\n context: z.array(z.string()).optional(),\n title: z.string().optional(),\n});\n\nconst optionsSchema = z.object({\n turnPolicy: z.nativeEnum(TurnPolicy).default(TurnPolicy.Steer),\n updateIntervalMs: z.number().finite().nonnegative().optional(),\n});\n\n// A room member as a principal: a person by user id, an agent by definition id.\nconst defaultAuthOf = (\n author: import('@finalai/agent-provider').ParticipantIface | undefined,\n): RoomAuthIface | null => {\n if (author == null) return null;\n return {\n principalId: author.userId ?? author.definitionId ?? author.id,\n principalType: author.userId == null ? RoomPrincipalType.Service : RoomPrincipalType.User,\n authenticator: 'final',\n displayName: author.displayName,\n attributes: { participant_id: author.id },\n };\n};\n\nexport const finalChannel = (\n inputOptions: FinalChannelOptionsIface = {},\n): RoomSurfaceDefinitionIface<JsonValue, JsonValue> => {\n const options = {\n ...inputOptions,\n events: inputOptions.events == null ? undefined : { ...inputOptions.events },\n };\n const callbacks = {\n onMessage: options.onMessage,\n onInputResponse: options.onInputResponse,\n renderer: options.renderer,\n route: options.route,\n ...options.events,\n };\n for (const [name, callback] of Object.entries(callbacks))\n if (callback != null && !z.function().safeParse(callback).success)\n throw new Error(`Final channel ${name} must be a function`);\n const supportedEvents = new Set([\n 'message.delta',\n 'message.completed',\n 'turn.started',\n 'turn.completed',\n 'decision.created',\n 'decision.resolved',\n ]);\n for (const kind of Object.keys(options.events ?? {}))\n if (!supportedEvents.has(kind)) throw new Error(`unsupported Final channel event: ${kind}`);\n const config = optionsSchema.parse(options);\n const base = createMessagingChannel({ ...config, route: options.route });\n const receive: typeof base.receive = async (input, ctx) => {\n if (conversationEventInboundSchema.safeParse(input).success) return base.receive(input, ctx);\n const parsed = messageInboundSchema.parse(input);\n const participants =\n ctx.participants ?? (await ctx.platform.conversations.participants(parsed.conversationId));\n const author = participants.find(\n (participant) => participant.id === parsed.authorParticipantId,\n );\n const message =\n ctx.message ??\n (await ctx.platform.conversations.postMessage({\n ...parsed,\n content: contentBlocksOf(parsed.content),\n }));\n if (ctx.definitionId == null) throw new Error('Final channel has no agent definition');\n const messageContext: FinalMessageContextIface = {\n ...ctx,\n defaultAuth: defaultAuthOf(author),\n };\n const accepted =\n options.onMessage == null\n ? { auth: messageContext.defaultAuth }\n : await options.onMessage(messageContext, message);\n const admission = accepted == null ? null : admissionSchema.parse(accepted);\n if (admission == null) return { conversationId: parsed.conversationId };\n const context = admission.context ?? [];\n const injected: ContentBlock[] = context.map((text) => ({ type: 'text', text }));\n return base.receive(\n {\n ...parsed,\n content: [...context.map((text) => ({ type: 'text', text })), ...parsed.content],\n },\n {\n ...ctx,\n platform: {\n ...ctx.platform,\n sessions: {\n ...ctx.platform.sessions,\n prompt: (args) =>\n ctx.platform.sessions.prompt({\n ...args,\n auth: admission.auth,\n title: admission.title,\n }),\n },\n },\n message: { ...message, content: [...injected, ...message.content] },\n },\n );\n };\n const channelContext = (ctx: ProjectionContextIface): FinalChannelContextIface => {\n const { conversation, agentParticipant } = ctx;\n if (conversation == null || agentParticipant == null || agentParticipant.definitionId == null)\n throw new Error('Final platform context requires a Final conversation');\n return {\n final: {\n post: async (message) => {\n if (ctx.platform.conversations.dispatchMessage == null)\n throw new Error('channel dispatch is unavailable');\n const posted = await ctx.platform.conversations.postMessage({\n conversationId: conversation.conversationId,\n authorParticipantId: agentParticipant.id,\n content: contentBlocksOf(message.content),\n clientMessageId: `channel:${ctx.turn.id}:${message.id}`,\n originTurnId: ctx.turn.id,\n });\n await ctx.platform.conversations.dispatchMessage({\n conversationId: posted.conversationId,\n messageId: posted.messageId,\n });\n return posted;\n },\n },\n };\n };\n const sessionContext = (ctx: ProjectionContextIface): FinalSessionContextIface => ({\n sessionId: ctx.sessionId ?? null,\n turnId: ctx.turn.id,\n state: ctx.state,\n });\n const wrap = <Data>(\n schema: z.ZodType<Data>,\n handler: FinalChannelEventHandler<Data> | undefined,\n ): RoomEventHandler | undefined =>\n handler == null\n ? undefined\n : async (event, ctx) =>\n handler(schema.parse(event.data), channelContext(ctx), sessionContext(ctx));\n const authoredEvents = {\n [SemanticChannelEventKind.MessageCompleted]: wrap(\n channelMessageCompletedSchema,\n options.events?.['message.completed'],\n ),\n [SemanticChannelEventKind.MessageDelta]: wrap(\n z.object({ messageId: z.string(), delta: jsonObjectSchema }),\n options.events?.['message.delta'],\n ),\n [SemanticChannelEventKind.TurnStarted]: wrap(\n z.object({ turnId: z.string() }),\n options.events?.['turn.started'],\n ),\n [SemanticChannelEventKind.TurnCompleted]: wrap(\n z.object({ turnId: z.string(), stopReason: z.string().nullable() }),\n options.events?.['turn.completed'],\n ),\n 'decision.created': wrap(decisionCreatedDataSchema, options.events?.['decision.created']),\n 'decision.resolved': wrap(decisionResolvedDataSchema, options.events?.['decision.resolved']),\n };\n const events = { ...base.events };\n for (const [kind, handler] of Object.entries(authoredEvents))\n if (handler != null) events[kind] = handler;\n return Object.freeze(\n defineRoomSurface({\n ...base,\n config: jsonObjectSchema.parse(config),\n configure: (next) =>\n finalChannel({ ...options, ...optionsSchema.parse({ ...config, ...next }) }),\n receive,\n respond: async (input, ctx) => {\n const conversation = z.string().min(1).parse(ctx.conversationId);\n const participants = await ctx.platform.conversations.participants(conversation);\n const author = participants.find(\n (participant) => participant.id === input.actorParticipantId,\n );\n const defaultAuth = defaultAuthOf(author);\n let admission: ChannelAdmissionIface = { auth: defaultAuth };\n if (options.onInputResponse != null) {\n const accepted = await options.onInputResponse({ ...ctx, defaultAuth }, input);\n if (accepted == null) return { resolved: false };\n admission = admissionSchema.parse(accepted);\n }\n if (ctx.platform.sessions.respond == null)\n throw new Error('response submission is unavailable');\n return ctx.platform.sessions.respond({ ...input, auth: admission.auth });\n },\n cancel: async (ctx) => {\n if (ctx.agentParticipantId == null) return { accepted: false };\n const conversation = z.string().min(1).parse(ctx.conversationId);\n const participants = await ctx.platform.conversations.participants(conversation);\n const agent = participants.find((participant) => participant.id === ctx.agentParticipantId);\n if (agent?.sessionId == null) return { accepted: false };\n await ctx.platform.sessions.cancel({\n participantId: agent.id,\n reason: ctx.cancelReason,\n throughMessageSeq: ctx.cancelThroughMessageSeq,\n });\n return { accepted: true };\n },\n project: async (update, ctx) => {\n const next = () =>\n options.events?.['message.completed'] == null\n ? base.project(update, ctx)\n : Promise.resolve();\n if (options.renderer != null) {\n await options.renderer(update, channelContext(ctx), sessionContext(ctx), next);\n return;\n }\n await next();\n },\n events: Object.freeze(events),\n }),\n );\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["RoomPrincipalType"]
7
7
  }
@@ -1,7 +1,7 @@
1
- import { channelMessageInputSchema } from "@finalai/agent-provider";
1
+ import { roomMessageInputSchema } from "@finalai/agent-provider";
2
2
  import * as z from "zod";
3
3
  import { MembershipChange } from "./delivery.mjs";
4
- const messageInboundSchema = channelMessageInputSchema;
4
+ const messageInboundSchema = roomMessageInputSchema;
5
5
  var ConversationEventKind = /* @__PURE__ */ ((ConversationEventKind2) => {
6
6
  ConversationEventKind2["Reaction"] = "reaction";
7
7
  ConversationEventKind2["Membership"] = "membership";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/channels/inbound.ts"],
4
- "sourcesContent": ["import { channelMessageInputSchema } from '@finalai/agent-provider';\nimport * as z from 'zod';\nimport { MembershipChange } from \"./delivery.mjs\";\n\n// What the messaging channels receive: a message for an existing conversation,\n// authored by one of its participants (the HTTP API, an isolate callback).\nexport const messageInboundSchema = channelMessageInputSchema;\n\nexport type MessageInboundIface = z.infer<typeof messageInboundSchema>;\n\nexport enum ConversationEventKind {\n Reaction = 'reaction',\n Membership = 'membership',\n}\n\n// Conversation events that reach agents as observe-only system blocks.\nexport const reactionInboundSchema = z.object({\n event: z.literal(ConversationEventKind.Reaction),\n conversationId: z.string().min(1),\n messageId: z.string().min(1),\n // The reacted message's position, so it is read back however old it is.\n messageSeq: z.number().int().positive(),\n // Whether it is its author's newest message (\"your last message\").\n latestOfAuthor: z.boolean(),\n reactorParticipantId: z.string().min(1),\n emoji: z.string().min(1),\n // A new persisted message revision distinguishes removing and re-adding a reaction.\n eventId: z.string().min(1).optional(),\n});\n\nexport const membershipInboundSchema = z.object({\n event: z.literal(ConversationEventKind.Membership),\n conversationId: z.string().min(1),\n participantId: z.string().min(1),\n change: z.nativeEnum(MembershipChange),\n // Distinguishes repeated joins and leaves of one participant.\n eventId: z.string().min(1),\n});\n\nexport const conversationEventInboundSchema = z.discriminatedUnion('event', [\n reactionInboundSchema,\n membershipInboundSchema,\n]);\n\nexport type ConversationEventInboundIface = z.infer<typeof conversationEventInboundSchema>;\n"],
5
- "mappings": "AAAA,SAAS,iCAAiC;AAC1C,YAAY,OAAO;AACnB,SAAS,wBAAwB;AAI1B,MAAM,uBAAuB;AAI7B,IAAK,wBAAL,kBAAKA,2BAAL;AACL,EAAAA,uBAAA,cAAW;AACX,EAAAA,uBAAA,gBAAa;AAFH,SAAAA;AAAA,GAAA;AAML,MAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,OAAO,EAAE,QAAQ,yBAA8B;AAAA,EAC/C,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAChC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAE3B,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA;AAAA,EAEtC,gBAAgB,EAAE,QAAQ;AAAA,EAC1B,sBAAsB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAEvB,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AACtC,CAAC;AAEM,MAAM,0BAA0B,EAAE,OAAO;AAAA,EAC9C,OAAO,EAAE,QAAQ,6BAAgC;AAAA,EACjD,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAChC,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,QAAQ,EAAE,WAAW,gBAAgB;AAAA;AAAA,EAErC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;AAC3B,CAAC;AAEM,MAAM,iCAAiC,EAAE,mBAAmB,SAAS;AAAA,EAC1E;AAAA,EACA;AACF,CAAC;",
4
+ "sourcesContent": ["import { roomMessageInputSchema } from '@finalai/agent-provider';\nimport * as z from 'zod';\nimport { MembershipChange } from \"./delivery.mjs\";\n\n// What the messaging channels receive: a message for an existing conversation,\n// authored by one of its participants (the HTTP API, an isolate callback).\nexport const messageInboundSchema = roomMessageInputSchema;\n\nexport type MessageInboundIface = z.infer<typeof messageInboundSchema>;\n\nexport enum ConversationEventKind {\n Reaction = 'reaction',\n Membership = 'membership',\n}\n\n// Conversation events that reach agents as observe-only system blocks.\nexport const reactionInboundSchema = z.object({\n event: z.literal(ConversationEventKind.Reaction),\n conversationId: z.string().min(1),\n messageId: z.string().min(1),\n // The reacted message's position, so it is read back however old it is.\n messageSeq: z.number().int().positive(),\n // Whether it is its author's newest message (\"your last message\").\n latestOfAuthor: z.boolean(),\n reactorParticipantId: z.string().min(1),\n emoji: z.string().min(1),\n // A new persisted message revision distinguishes removing and re-adding a reaction.\n eventId: z.string().min(1).optional(),\n});\n\nexport const membershipInboundSchema = z.object({\n event: z.literal(ConversationEventKind.Membership),\n conversationId: z.string().min(1),\n participantId: z.string().min(1),\n change: z.nativeEnum(MembershipChange),\n // Distinguishes repeated joins and leaves of one participant.\n eventId: z.string().min(1),\n});\n\nexport const conversationEventInboundSchema = z.discriminatedUnion('event', [\n reactionInboundSchema,\n membershipInboundSchema,\n]);\n\nexport type ConversationEventInboundIface = z.infer<typeof conversationEventInboundSchema>;\n"],
5
+ "mappings": "AAAA,SAAS,8BAA8B;AACvC,YAAY,OAAO;AACnB,SAAS,wBAAwB;AAI1B,MAAM,uBAAuB;AAI7B,IAAK,wBAAL,kBAAKA,2BAAL;AACL,EAAAA,uBAAA,cAAW;AACX,EAAAA,uBAAA,gBAAa;AAFH,SAAAA;AAAA,GAAA;AAML,MAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,OAAO,EAAE,QAAQ,yBAA8B;AAAA,EAC/C,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAChC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAE3B,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA;AAAA,EAEtC,gBAAgB,EAAE,QAAQ;AAAA,EAC1B,sBAAsB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAEvB,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AACtC,CAAC;AAEM,MAAM,0BAA0B,EAAE,OAAO;AAAA,EAC9C,OAAO,EAAE,QAAQ,6BAAgC;AAAA,EACjD,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAChC,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,QAAQ,EAAE,WAAW,gBAAgB;AAAA;AAAA,EAErC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;AAC3B,CAAC;AAEM,MAAM,iCAAiC,EAAE,mBAAmB,SAAS;AAAA,EAC1E;AAAA,EACA;AACF,CAAC;",
6
6
  "names": ["ConversationEventKind"]
7
7
  }
@@ -7,10 +7,3 @@ export * from "./messaging-channel.mjs";
7
7
  export * from "./projection.mjs";
8
8
  export * from "./prompt.mjs";
9
9
  export * from "./routing.mjs";
10
- export * from "./slack.mjs";
11
- export * from "./discord.mjs";
12
- export * from "./github.mjs";
13
- export * from "./linear.mjs";
14
- export * from "./webhook.mjs";
15
- export * from "./voice.mjs";
16
- export * from "./phone.mjs";
@@ -7,11 +7,4 @@ export * from "./messaging-channel.mjs";
7
7
  export * from "./projection.mjs";
8
8
  export * from "./prompt.mjs";
9
9
  export * from "./routing.mjs";
10
- export * from "./slack.mjs";
11
- export * from "./discord.mjs";
12
- export * from "./github.mjs";
13
- export * from "./linear.mjs";
14
- export * from "./webhook.mjs";
15
- export * from "./voice.mjs";
16
- export * from "./phone.mjs";
17
10
  //# sourceMappingURL=index.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/channels/index.ts"],
4
- "sourcesContent": ["export * from \"./content.mjs\";\nexport * from \"./delivery.mjs\";\nexport * from \"./direct-messaging.mjs\";\nexport * from \"./group-messaging.mjs\";\nexport * from \"./inbound.mjs\";\nexport * from \"./messaging-channel.mjs\";\nexport * from \"./projection.mjs\";\nexport * from \"./prompt.mjs\";\nexport * from \"./routing.mjs\";\nexport * from \"./slack.mjs\";\nexport * from \"./discord.mjs\";\nexport * from \"./github.mjs\";\nexport * from \"./linear.mjs\";\nexport * from \"./webhook.mjs\";\nexport * from \"./voice.mjs\";\nexport * from \"./phone.mjs\";\n"],
5
- "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
4
+ "sourcesContent": ["export * from \"./content.mjs\";\nexport * from \"./delivery.mjs\";\nexport * from \"./direct-messaging.mjs\";\nexport * from \"./group-messaging.mjs\";\nexport * from \"./inbound.mjs\";\nexport * from \"./messaging-channel.mjs\";\nexport * from \"./projection.mjs\";\nexport * from \"./prompt.mjs\";\nexport * from \"./routing.mjs\";\n"],
5
+ "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import type { ContentBlock } from '@agentclientprotocol/sdk/experimental/v2';
2
2
  import { type FinalAuthorIface, type FinalContextIface, type FinalMessageRefIface } from '@finalai/acp-session';
3
- import { type ChannelAuthIface, type ConversationMessageIface, type ParticipantIface } from '@finalai/agent-provider/channel';
3
+ import { type RoomAuthIface, type ConversationMessageIface, type ParticipantIface } from '@finalai/agent-provider/room-surface';
4
4
  export declare const EXCERPT_CHARS = 280;
5
5
  export declare const CATCH_UP_MAX_MESSAGES = 20;
6
6
  export declare const CATCH_UP_MAX_CHARS = 4000;
@@ -10,7 +10,7 @@ export declare const messageSummary: (content: ContentBlock[]) => string;
10
10
  export declare const excerpt: (text: string, maxChars?: number) => string;
11
11
  export declare const finalAuthorOf: (participant: ParticipantIface) => FinalAuthorIface;
12
12
  export declare const principalAuthorOf: (args: {
13
- auth: ChannelAuthIface;
13
+ auth: RoomAuthIface;
14
14
  agent?: boolean;
15
15
  }) => FinalAuthorIface;
16
16
  export interface AuthorPrefixedContentArgsIface {
@@ -6,12 +6,12 @@ import {
6
6
  withFinalMeta
7
7
  } from "@finalai/acp-session";
8
8
  import {
9
- ChannelPrincipalType,
9
+ RoomPrincipalType,
10
10
  MessageKind,
11
11
  ParticipantKind,
12
12
  principalDisplayName,
13
13
  RoutingMode
14
- } from "@finalai/agent-provider/channel";
14
+ } from "@finalai/agent-provider/room-surface";
15
15
  const EXCERPT_CHARS = 280;
16
16
  const CATCH_UP_MAX_MESSAGES = 20;
17
17
  const CATCH_UP_MAX_CHARS = 4e3;
@@ -35,7 +35,7 @@ const finalAuthorOf = (participant) => ({
35
35
  displayName: participant.displayName
36
36
  });
37
37
  const principalAuthorOf = (args) => ({
38
- kind: args.agent === true ? FinalAuthorKind.Agent : args.auth.principalType === ChannelPrincipalType.User ? FinalAuthorKind.User : FinalAuthorKind.Service,
38
+ kind: args.agent === true ? FinalAuthorKind.Agent : args.auth.principalType === RoomPrincipalType.User ? FinalAuthorKind.User : FinalAuthorKind.Service,
39
39
  displayName: principalDisplayName(args.auth),
40
40
  principal: {
41
41
  principalId: args.auth.principalId,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/channels/prompt.ts"],
4
- "sourcesContent": ["import type { ContentBlock } from '@agentclientprotocol/sdk/experimental/v2';\nimport {\n FinalAuthorKind,\n FinalContentRole,\n promptTextWithAuthorPrefix,\n textOf,\n withFinalMeta,\n type FinalAuthorIface,\n type FinalContextIface,\n type FinalMessageRefIface,\n} from '@finalai/acp-session';\nimport {\n ChannelPrincipalType,\n MessageKind,\n ParticipantKind,\n principalDisplayName,\n RoutingMode,\n type ChannelAuthIface,\n type ConversationMessageIface,\n type ParticipantIface,\n} from '@finalai/agent-provider/channel';\n\nexport const EXCERPT_CHARS = 280;\nexport const CATCH_UP_MAX_MESSAGES = 20;\nexport const CATCH_UP_MAX_CHARS = 4_000;\n\nexport const textBlock = (text: string): ContentBlock => ({ type: 'text', text });\n\nexport const contentText = (content: ContentBlock[]): string =>\n textOf(content, { separator: '\\n' }).trim();\n\n// A one-line description of a message for previews, excerpts and transcripts.\nexport const messageSummary = (content: ContentBlock[]): string => {\n const text = contentText(content);\n if (text.length > 0) {\n return text;\n }\n const attachments = content.filter((block) => block.type !== 'text').length;\n return attachments === 0 ? '' : `[${attachments} attachment${attachments === 1 ? '' : 's'}]`;\n};\n\nexport const excerpt = (text: string, maxChars: number = EXCERPT_CHARS): string => {\n const normalized = text.replace(/\\s+/gu, ' ').trim();\n return normalized.length <= maxChars ? normalized : `${normalized.slice(0, maxChars - 1)}\u2026`;\n};\n\nexport const finalAuthorOf = (participant: ParticipantIface): FinalAuthorIface => ({\n participantId: participant.id,\n kind: participant.kind === ParticipantKind.Agent ? FinalAuthorKind.Agent : FinalAuthorKind.User,\n displayName: participant.displayName,\n});\n\n// The author an agent sees for channel input from no member: the principal the\n// channel authenticated, named as the channel named it. `agent` marks input an\n// agent wrote elsewhere (another chat), so the recipient knows it is not a person.\nexport const principalAuthorOf = (args: {\n auth: ChannelAuthIface;\n agent?: boolean;\n}): FinalAuthorIface => ({\n kind:\n args.agent === true\n ? FinalAuthorKind.Agent\n : args.auth.principalType === ChannelPrincipalType.User\n ? FinalAuthorKind.User\n : FinalAuthorKind.Service,\n displayName: principalDisplayName(args.auth),\n principal: {\n principalId: args.auth.principalId,\n principalType: args.auth.principalType,\n authenticator: args.auth.authenticator,\n },\n});\n\nconst withContentRole = (block: ContentBlock, context?: FinalContextIface): ContentBlock =>\n withFinalMeta(block, { role: FinalContentRole.Context, context });\n\n// Attribution: `_meta[\"final.ai\"].author` on every block, plus a\n// `<name>: ` prefix for harnesses that do not render author meta.\nexport interface AuthorPrefixedContentArgsIface {\n content: ContentBlock[];\n author: FinalAuthorIface;\n rendersAuthorMeta: boolean;\n context?: FinalContextIface;\n}\n\nexport const authorPrefixedContent = (args: AuthorPrefixedContentArgsIface): ContentBlock[] => {\n const blocks: ContentBlock[] = args.rendersAuthorMeta\n ? args.content\n : promptTextWithAuthorPrefix(args.content, args.author.displayName);\n return blocks.map((block, index) =>\n withFinalMeta(block, { author: args.author, context: index === 0 ? args.context : undefined }),\n );\n};\n\nexport interface ReplyContextArgsIface {\n replyTo?: FinalMessageRefIface | null;\n thread?: {\n rootMessageId: string;\n rootExcerpt: string;\n rootAuthor?: FinalAuthorIface | null;\n } | null;\n quotes?: FinalMessageRefIface[];\n}\n\nexport const finalContextOf = (args: ReplyContextArgsIface): FinalContextIface | undefined => {\n const context: FinalContextIface = {};\n if (args.replyTo != null) context.replyTo = args.replyTo;\n if (args.thread != null) {\n context.thread = {\n rootMessageId: args.thread.rootMessageId,\n rootExcerpt: args.thread.rootExcerpt,\n };\n }\n if (args.quotes != null && args.quotes.length > 0) context.quotes = args.quotes;\n return Object.keys(context).length === 0 ? undefined : context;\n};\n\n// The rendered reply/thread/quote block, for harnesses that ignore\n// `_meta`. Null when the message has no context.\nexport const renderReplyContext = (args: ReplyContextArgsIface): ContentBlock | null => {\n const context = finalContextOf(args);\n if (context == null) {\n return null;\n }\n const lines: string[] = [];\n if (args.thread != null) {\n const by =\n args.thread.rootAuthor == null ? '' : ` started by ${args.thread.rootAuthor.displayName}`;\n lines.push(`In a thread${by}: \"${args.thread.rootExcerpt}\"`);\n }\n if (args.replyTo != null) {\n lines.push(\n `Replying to ${args.replyTo.author?.displayName ?? 'a message'}: \"${args.replyTo.excerpt}\"`,\n );\n }\n for (const quote of args.quotes ?? []) {\n lines.push(`Quoting ${quote.author?.displayName ?? 'a message'}: \"${quote.excerpt}\"`);\n }\n return withContentRole(textBlock(lines.join('\\n')), context);\n};\n\nexport const messageRefOf = (\n message: ConversationMessageIface,\n participants: ParticipantIface[],\n): FinalMessageRefIface => {\n const author = participants.find((participant) => participant.id === message.authorParticipantId);\n return {\n messageId: message.messageId,\n author: author == null ? null : finalAuthorOf(author),\n excerpt: excerpt(messageSummary(message.content)),\n };\n};\n\nconst transcriptLine = (\n message: ConversationMessageIface,\n participants: ParticipantIface[],\n): string => {\n const author = participants.find((participant) => participant.id === message.authorParticipantId);\n return `${author?.displayName ?? 'Someone'}: ${messageSummary(message.content)}`;\n};\n\nconst visibleForTranscript = (message: ConversationMessageIface): boolean =>\n message.kind !== MessageKind.Card && messageSummary(message.content).length > 0;\n\ninterface BoundedLinesArgsIface {\n messages: ConversationMessageIface[];\n participants: ParticipantIface[];\n maxMessages: number;\n maxChars: number;\n}\n\ninterface BoundedLinesIface {\n lines: string[];\n omitted: number;\n}\n\n// Lines from newest backwards until a bound is hit, returned oldest first.\nconst boundedLines = (args: BoundedLinesArgsIface): BoundedLinesIface => {\n const lines: string[] = [];\n let chars = 0;\n const ordered = [...args.messages].sort((left, right) => right.seq - left.seq);\n for (const message of ordered) {\n const line = transcriptLine(message, args.participants);\n if (lines.length >= args.maxMessages || chars + line.length > args.maxChars) {\n break;\n }\n lines.push(line);\n chars += line.length + 1;\n }\n return { lines: lines.reverse(), omitted: ordered.length - lines.length };\n};\n\nexport enum CatchUpSince {\n // A session that has never seen this conversation (new or reset).\n Start = 'start',\n // An agent that does not observe: since it last spoke or was mentioned.\n LastContact = 'last-contact',\n}\n\nexport interface CatchUpArgsIface {\n // Messages before the one being delivered, any order.\n messages: ConversationMessageIface[];\n participants: ParticipantIface[];\n agentParticipantId: string;\n since: CatchUpSince;\n maxMessages?: number;\n maxChars?: number;\n}\n\n// \"Earlier in this conversation, not previously shown: \u2026\", marked\n// as context. Null when there is nothing the agent has not seen.\nexport const buildCatchUpBlock = (args: CatchUpArgsIface): ContentBlock | null => {\n let unseen = args.messages.filter(\n (message) =>\n visibleForTranscript(message) && message.authorParticipantId !== args.agentParticipantId,\n );\n if (args.since === CatchUpSince.LastContact) {\n const lastContactSeq = args.messages.reduce(\n (latest, message) =>\n message.authorParticipantId === args.agentParticipantId ||\n message.mentionedParticipantIds.includes(args.agentParticipantId)\n ? Math.max(latest, message.seq)\n : latest,\n -1,\n );\n unseen = unseen.filter((message) => message.seq > lastContactSeq);\n }\n if (unseen.length === 0) {\n return null;\n }\n const { lines, omitted } = boundedLines({\n messages: unseen,\n participants: args.participants,\n maxMessages: args.maxMessages ?? CATCH_UP_MAX_MESSAGES,\n maxChars: args.maxChars ?? CATCH_UP_MAX_CHARS,\n });\n if (lines.length === 0) {\n return null;\n }\n const header = 'Earlier in this conversation, not previously shown:';\n const omittedLine =\n omitted > 0 ? [`(${omitted} earlier message${omitted === 1 ? '' : 's'} omitted)`] : [];\n return withContentRole(textBlock([header, ...omittedLine, ...lines].join('\\n')));\n};\n\n// A notice from Final itself delivered by observe: reactions, membership changes.\nexport const systemNoticeBlock = (args: { text: string }): ContentBlock =>\n withFinalMeta(textBlock(args.text), {\n author: { kind: FinalAuthorKind.Service, displayName: 'Final' },\n });\n\n// What a recipient has not seen of its conversation before a prompt: a fresh\n// session has seen nothing; a Mention agent sees only what it is prompted\n// with; everyone else has been observing.\nexport const catchUpFor = (args: {\n recipient: ParticipantIface;\n earlier: ConversationMessageIface[];\n participants: ParticipantIface[];\n}): ContentBlock | null => {\n const since =\n args.recipient.sessionId == null\n ? CatchUpSince.Start\n : args.recipient.routingMode === RoutingMode.Mention\n ? CatchUpSince.LastContact\n : null;\n if (since == null) return null;\n return buildCatchUpBlock({\n messages: args.earlier,\n participants: args.participants,\n agentParticipantId: args.recipient.id,\n since,\n });\n};\n\nexport interface PromptContentArgsIface {\n message: ConversationMessageIface;\n author: ParticipantIface;\n recipient: ParticipantIface;\n replyContext: ReplyContextArgsIface;\n catchUp: ContentBlock | null;\n}\n\n// The ACP prompt one agent receives for a conversation message.\nexport const buildPromptContent = (args: PromptContentArgsIface): ContentBlock[] => {\n const contextBlock = renderReplyContext(args.replyContext);\n const body = authorPrefixedContent({\n content:\n args.message.content.length > 0 ? args.message.content : [textBlock(args.message.body)],\n author: finalAuthorOf(args.author),\n rendersAuthorMeta: args.recipient.rendersAuthorMeta ?? false,\n context: finalContextOf(args.replyContext),\n });\n return [\n ...(args.catchUp == null ? [] : [args.catchUp]),\n ...(contextBlock == null ? [] : [contextBlock]),\n ...body,\n ];\n};\n\nexport interface ServiceInputPromptArgsIface {\n content: ContentBlock[];\n // Channel-supplied context lines, marked as context before the input.\n context?: string[];\n author: FinalAuthorIface;\n recipient: ParticipantIface;\n // The room's latest messages when the input is delivered, any order.\n earlier: ConversationMessageIface[];\n participants: ParticipantIface[];\n}\n\n// The ACP prompt a room's agent receives for channel input: what it has not seen\n// of the room up to its latest message, then the input attributed to its principal.\nexport const buildServiceInputPrompt = (args: ServiceInputPromptArgsIface): ContentBlock[] => {\n const catchUp = catchUpFor({\n recipient: args.recipient,\n earlier: args.earlier,\n participants: args.participants,\n });\n return [\n ...(catchUp == null ? [] : [catchUp]),\n ...(args.context ?? []).map((text) => withContentRole(textBlock(text))),\n ...authorPrefixedContent({\n content: args.content,\n author: args.author,\n rendersAuthorMeta: args.recipient.rendersAuthorMeta ?? false,\n }),\n ];\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { ContentBlock } from '@agentclientprotocol/sdk/experimental/v2';\nimport {\n FinalAuthorKind,\n FinalContentRole,\n promptTextWithAuthorPrefix,\n textOf,\n withFinalMeta,\n type FinalAuthorIface,\n type FinalContextIface,\n type FinalMessageRefIface,\n} from '@finalai/acp-session';\nimport {\n RoomPrincipalType,\n MessageKind,\n ParticipantKind,\n principalDisplayName,\n RoutingMode,\n type RoomAuthIface,\n type ConversationMessageIface,\n type ParticipantIface,\n} from '@finalai/agent-provider/room-surface';\n\nexport const EXCERPT_CHARS = 280;\nexport const CATCH_UP_MAX_MESSAGES = 20;\nexport const CATCH_UP_MAX_CHARS = 4_000;\n\nexport const textBlock = (text: string): ContentBlock => ({ type: 'text', text });\n\nexport const contentText = (content: ContentBlock[]): string =>\n textOf(content, { separator: '\\n' }).trim();\n\n// A one-line description of a message for previews, excerpts and transcripts.\nexport const messageSummary = (content: ContentBlock[]): string => {\n const text = contentText(content);\n if (text.length > 0) {\n return text;\n }\n const attachments = content.filter((block) => block.type !== 'text').length;\n return attachments === 0 ? '' : `[${attachments} attachment${attachments === 1 ? '' : 's'}]`;\n};\n\nexport const excerpt = (text: string, maxChars: number = EXCERPT_CHARS): string => {\n const normalized = text.replace(/\\s+/gu, ' ').trim();\n return normalized.length <= maxChars ? normalized : `${normalized.slice(0, maxChars - 1)}\u2026`;\n};\n\nexport const finalAuthorOf = (participant: ParticipantIface): FinalAuthorIface => ({\n participantId: participant.id,\n kind: participant.kind === ParticipantKind.Agent ? FinalAuthorKind.Agent : FinalAuthorKind.User,\n displayName: participant.displayName,\n});\n\n// The author an agent sees for channel input from no member: the principal the\n// channel authenticated, named as the channel named it. `agent` marks input an\n// agent wrote elsewhere (another chat), so the recipient knows it is not a person.\nexport const principalAuthorOf = (args: {\n auth: RoomAuthIface;\n agent?: boolean;\n}): FinalAuthorIface => ({\n kind:\n args.agent === true\n ? FinalAuthorKind.Agent\n : args.auth.principalType === RoomPrincipalType.User\n ? FinalAuthorKind.User\n : FinalAuthorKind.Service,\n displayName: principalDisplayName(args.auth),\n principal: {\n principalId: args.auth.principalId,\n principalType: args.auth.principalType,\n authenticator: args.auth.authenticator,\n },\n});\n\nconst withContentRole = (block: ContentBlock, context?: FinalContextIface): ContentBlock =>\n withFinalMeta(block, { role: FinalContentRole.Context, context });\n\n// Attribution: `_meta[\"final.ai\"].author` on every block, plus a\n// `<name>: ` prefix for harnesses that do not render author meta.\nexport interface AuthorPrefixedContentArgsIface {\n content: ContentBlock[];\n author: FinalAuthorIface;\n rendersAuthorMeta: boolean;\n context?: FinalContextIface;\n}\n\nexport const authorPrefixedContent = (args: AuthorPrefixedContentArgsIface): ContentBlock[] => {\n const blocks: ContentBlock[] = args.rendersAuthorMeta\n ? args.content\n : promptTextWithAuthorPrefix(args.content, args.author.displayName);\n return blocks.map((block, index) =>\n withFinalMeta(block, { author: args.author, context: index === 0 ? args.context : undefined }),\n );\n};\n\nexport interface ReplyContextArgsIface {\n replyTo?: FinalMessageRefIface | null;\n thread?: {\n rootMessageId: string;\n rootExcerpt: string;\n rootAuthor?: FinalAuthorIface | null;\n } | null;\n quotes?: FinalMessageRefIface[];\n}\n\nexport const finalContextOf = (args: ReplyContextArgsIface): FinalContextIface | undefined => {\n const context: FinalContextIface = {};\n if (args.replyTo != null) context.replyTo = args.replyTo;\n if (args.thread != null) {\n context.thread = {\n rootMessageId: args.thread.rootMessageId,\n rootExcerpt: args.thread.rootExcerpt,\n };\n }\n if (args.quotes != null && args.quotes.length > 0) context.quotes = args.quotes;\n return Object.keys(context).length === 0 ? undefined : context;\n};\n\n// The rendered reply/thread/quote block, for harnesses that ignore\n// `_meta`. Null when the message has no context.\nexport const renderReplyContext = (args: ReplyContextArgsIface): ContentBlock | null => {\n const context = finalContextOf(args);\n if (context == null) {\n return null;\n }\n const lines: string[] = [];\n if (args.thread != null) {\n const by =\n args.thread.rootAuthor == null ? '' : ` started by ${args.thread.rootAuthor.displayName}`;\n lines.push(`In a thread${by}: \"${args.thread.rootExcerpt}\"`);\n }\n if (args.replyTo != null) {\n lines.push(\n `Replying to ${args.replyTo.author?.displayName ?? 'a message'}: \"${args.replyTo.excerpt}\"`,\n );\n }\n for (const quote of args.quotes ?? []) {\n lines.push(`Quoting ${quote.author?.displayName ?? 'a message'}: \"${quote.excerpt}\"`);\n }\n return withContentRole(textBlock(lines.join('\\n')), context);\n};\n\nexport const messageRefOf = (\n message: ConversationMessageIface,\n participants: ParticipantIface[],\n): FinalMessageRefIface => {\n const author = participants.find((participant) => participant.id === message.authorParticipantId);\n return {\n messageId: message.messageId,\n author: author == null ? null : finalAuthorOf(author),\n excerpt: excerpt(messageSummary(message.content)),\n };\n};\n\nconst transcriptLine = (\n message: ConversationMessageIface,\n participants: ParticipantIface[],\n): string => {\n const author = participants.find((participant) => participant.id === message.authorParticipantId);\n return `${author?.displayName ?? 'Someone'}: ${messageSummary(message.content)}`;\n};\n\nconst visibleForTranscript = (message: ConversationMessageIface): boolean =>\n message.kind !== MessageKind.Card && messageSummary(message.content).length > 0;\n\ninterface BoundedLinesArgsIface {\n messages: ConversationMessageIface[];\n participants: ParticipantIface[];\n maxMessages: number;\n maxChars: number;\n}\n\ninterface BoundedLinesIface {\n lines: string[];\n omitted: number;\n}\n\n// Lines from newest backwards until a bound is hit, returned oldest first.\nconst boundedLines = (args: BoundedLinesArgsIface): BoundedLinesIface => {\n const lines: string[] = [];\n let chars = 0;\n const ordered = [...args.messages].sort((left, right) => right.seq - left.seq);\n for (const message of ordered) {\n const line = transcriptLine(message, args.participants);\n if (lines.length >= args.maxMessages || chars + line.length > args.maxChars) {\n break;\n }\n lines.push(line);\n chars += line.length + 1;\n }\n return { lines: lines.reverse(), omitted: ordered.length - lines.length };\n};\n\nexport enum CatchUpSince {\n // A session that has never seen this conversation (new or reset).\n Start = 'start',\n // An agent that does not observe: since it last spoke or was mentioned.\n LastContact = 'last-contact',\n}\n\nexport interface CatchUpArgsIface {\n // Messages before the one being delivered, any order.\n messages: ConversationMessageIface[];\n participants: ParticipantIface[];\n agentParticipantId: string;\n since: CatchUpSince;\n maxMessages?: number;\n maxChars?: number;\n}\n\n// \"Earlier in this conversation, not previously shown: \u2026\", marked\n// as context. Null when there is nothing the agent has not seen.\nexport const buildCatchUpBlock = (args: CatchUpArgsIface): ContentBlock | null => {\n let unseen = args.messages.filter(\n (message) =>\n visibleForTranscript(message) && message.authorParticipantId !== args.agentParticipantId,\n );\n if (args.since === CatchUpSince.LastContact) {\n const lastContactSeq = args.messages.reduce(\n (latest, message) =>\n message.authorParticipantId === args.agentParticipantId ||\n message.mentionedParticipantIds.includes(args.agentParticipantId)\n ? Math.max(latest, message.seq)\n : latest,\n -1,\n );\n unseen = unseen.filter((message) => message.seq > lastContactSeq);\n }\n if (unseen.length === 0) {\n return null;\n }\n const { lines, omitted } = boundedLines({\n messages: unseen,\n participants: args.participants,\n maxMessages: args.maxMessages ?? CATCH_UP_MAX_MESSAGES,\n maxChars: args.maxChars ?? CATCH_UP_MAX_CHARS,\n });\n if (lines.length === 0) {\n return null;\n }\n const header = 'Earlier in this conversation, not previously shown:';\n const omittedLine =\n omitted > 0 ? [`(${omitted} earlier message${omitted === 1 ? '' : 's'} omitted)`] : [];\n return withContentRole(textBlock([header, ...omittedLine, ...lines].join('\\n')));\n};\n\n// A notice from Final itself delivered by observe: reactions, membership changes.\nexport const systemNoticeBlock = (args: { text: string }): ContentBlock =>\n withFinalMeta(textBlock(args.text), {\n author: { kind: FinalAuthorKind.Service, displayName: 'Final' },\n });\n\n// What a recipient has not seen of its conversation before a prompt: a fresh\n// session has seen nothing; a Mention agent sees only what it is prompted\n// with; everyone else has been observing.\nexport const catchUpFor = (args: {\n recipient: ParticipantIface;\n earlier: ConversationMessageIface[];\n participants: ParticipantIface[];\n}): ContentBlock | null => {\n const since =\n args.recipient.sessionId == null\n ? CatchUpSince.Start\n : args.recipient.routingMode === RoutingMode.Mention\n ? CatchUpSince.LastContact\n : null;\n if (since == null) return null;\n return buildCatchUpBlock({\n messages: args.earlier,\n participants: args.participants,\n agentParticipantId: args.recipient.id,\n since,\n });\n};\n\nexport interface PromptContentArgsIface {\n message: ConversationMessageIface;\n author: ParticipantIface;\n recipient: ParticipantIface;\n replyContext: ReplyContextArgsIface;\n catchUp: ContentBlock | null;\n}\n\n// The ACP prompt one agent receives for a conversation message.\nexport const buildPromptContent = (args: PromptContentArgsIface): ContentBlock[] => {\n const contextBlock = renderReplyContext(args.replyContext);\n const body = authorPrefixedContent({\n content:\n args.message.content.length > 0 ? args.message.content : [textBlock(args.message.body)],\n author: finalAuthorOf(args.author),\n rendersAuthorMeta: args.recipient.rendersAuthorMeta ?? false,\n context: finalContextOf(args.replyContext),\n });\n return [\n ...(args.catchUp == null ? [] : [args.catchUp]),\n ...(contextBlock == null ? [] : [contextBlock]),\n ...body,\n ];\n};\n\nexport interface ServiceInputPromptArgsIface {\n content: ContentBlock[];\n // Channel-supplied context lines, marked as context before the input.\n context?: string[];\n author: FinalAuthorIface;\n recipient: ParticipantIface;\n // The room's latest messages when the input is delivered, any order.\n earlier: ConversationMessageIface[];\n participants: ParticipantIface[];\n}\n\n// The ACP prompt a room's agent receives for channel input: what it has not seen\n// of the room up to its latest message, then the input attributed to its principal.\nexport const buildServiceInputPrompt = (args: ServiceInputPromptArgsIface): ContentBlock[] => {\n const catchUp = catchUpFor({\n recipient: args.recipient,\n earlier: args.earlier,\n participants: args.participants,\n });\n return [\n ...(catchUp == null ? [] : [catchUp]),\n ...(args.context ?? []).map((text) => withContentRole(textBlock(text))),\n ...authorPrefixedContent({\n content: args.content,\n author: args.author,\n rendersAuthorMeta: args.recipient.rendersAuthorMeta ?? false,\n }),\n ];\n};\n"],
5
+ "mappings": "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",
6
6
  "names": ["CatchUpSince"]
7
7
  }
@@ -1,4 +1,4 @@
1
- import { type ParticipantIface, type RouteArgsIface, type RouteDecisionIface } from '@finalai/agent-provider/channel';
1
+ import { type ParticipantIface, type RouteArgsIface, type RouteDecisionIface } from '@finalai/agent-provider/room-surface';
2
2
  export declare const MAX_AGENT_HOP_DEPTH = 2;
3
3
  export declare const effectiveDefaultAgent: (participants: ParticipantIface[]) => ParticipantIface | null;
4
4
  export declare const routeMessage: (args: RouteArgsIface) => RouteDecisionIface[];
@@ -3,7 +3,7 @@ import {
3
3
  Delivery,
4
4
  ParticipantKind,
5
5
  RoutingMode
6
- } from "@finalai/agent-provider/channel";
6
+ } from "@finalai/agent-provider/room-surface";
7
7
  const MAX_AGENT_HOP_DEPTH = 2;
8
8
  const activeAgents = (participants) => participants.filter(
9
9
  (participant) => participant.kind === ParticipantKind.Agent && !participant.left
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/channels/routing.ts"],
4
- "sourcesContent": ["import {\n ConversationKind,\n Delivery,\n ParticipantKind,\n RoutingMode,\n type ParticipantIface,\n type RouteArgsIface,\n type RouteDecisionIface,\n} from '@finalai/agent-provider/channel';\n\n// Agent-authored messages may prompt other agents only while the chain of\n// agent hops that produced them is shorter than this: a human\n// message (0) prompts A, A's reply (1) may prompt B, B's reply (2) prompts no one.\nexport const MAX_AGENT_HOP_DEPTH = 2;\n\nconst activeAgents = (participants: ParticipantIface[]): ParticipantIface[] =>\n participants.filter(\n (participant) => participant.kind === ParticipantKind.Agent && !participant.left,\n );\n\n// The agent a no-mention message goes to: the Default agent, else (no Default)\n// the earliest-joined All agent, which then acts as the Default. Participants\n// arrive in join order.\nexport const effectiveDefaultAgent = (\n participants: ParticipantIface[],\n): ParticipantIface | null => {\n const agents = activeAgents(participants);\n return (\n agents.find((agent) => agent.routingMode === RoutingMode.Default) ??\n agents.find((agent) => agent.routingMode === RoutingMode.All) ??\n null\n );\n};\n\n// Pure: who gets a message and how. Users never receive decisions.\nexport const routeMessage = (args: RouteArgsIface): RouteDecisionIface[] => {\n const { conversation, message, participants } = args;\n const agents = activeAgents(participants).filter(\n (agent) =>\n agent.id !== message.authorParticipantId &&\n (message.agentAuthorDefinitionId == null ||\n agent.definitionId !== message.agentAuthorDefinitionId),\n );\n if (agents.length === 0) {\n return [];\n }\n const mentioned = new Set(message.mentionedParticipantIds);\n const mayPrompt = message.hopDepth < MAX_AGENT_HOP_DEPTH;\n const promptDelivery = mayPrompt ? Delivery.Prompt : Delivery.Observe;\n\n if (conversation.kind === ConversationKind.Direct) {\n return agents.map((agent) => ({ participantId: agent.id, delivery: promptDelivery }));\n }\n\n const anyAgentMentioned = agents.some((agent) => mentioned.has(agent.id));\n const defaultAgent = effectiveDefaultAgent(participants);\n return agents.flatMap((agent): RouteDecisionIface[] => {\n if (mentioned.has(agent.id)) {\n return [{ participantId: agent.id, delivery: promptDelivery }];\n }\n if (agent.routingMode === RoutingMode.Mention || agent.routingMode == null) {\n return [];\n }\n if (!anyAgentMentioned && agent.id === defaultAgent?.id) {\n return [{ participantId: agent.id, delivery: promptDelivery }];\n }\n return [{ participantId: agent.id, delivery: Delivery.Observe }];\n });\n};\n\nexport const routeToParticipant =\n (participantId: string) =>\n (args: RouteArgsIface): RouteDecisionIface[] =>\n args.participants.some(\n (participant) =>\n participant.id === participantId &&\n participant.kind === ParticipantKind.Agent &&\n !participant.left,\n )\n ? [{ participantId, delivery: Delivery.Prompt }]\n : [];\n"],
4
+ "sourcesContent": ["import {\n ConversationKind,\n Delivery,\n ParticipantKind,\n RoutingMode,\n type ParticipantIface,\n type RouteArgsIface,\n type RouteDecisionIface,\n} from '@finalai/agent-provider/room-surface';\n\n// Agent-authored messages may prompt other agents only while the chain of\n// agent hops that produced them is shorter than this: a human\n// message (0) prompts A, A's reply (1) may prompt B, B's reply (2) prompts no one.\nexport const MAX_AGENT_HOP_DEPTH = 2;\n\nconst activeAgents = (participants: ParticipantIface[]): ParticipantIface[] =>\n participants.filter(\n (participant) => participant.kind === ParticipantKind.Agent && !participant.left,\n );\n\n// The agent a no-mention message goes to: the Default agent, else (no Default)\n// the earliest-joined All agent, which then acts as the Default. Participants\n// arrive in join order.\nexport const effectiveDefaultAgent = (\n participants: ParticipantIface[],\n): ParticipantIface | null => {\n const agents = activeAgents(participants);\n return (\n agents.find((agent) => agent.routingMode === RoutingMode.Default) ??\n agents.find((agent) => agent.routingMode === RoutingMode.All) ??\n null\n );\n};\n\n// Pure: who gets a message and how. Users never receive decisions.\nexport const routeMessage = (args: RouteArgsIface): RouteDecisionIface[] => {\n const { conversation, message, participants } = args;\n const agents = activeAgents(participants).filter(\n (agent) =>\n agent.id !== message.authorParticipantId &&\n (message.agentAuthorDefinitionId == null ||\n agent.definitionId !== message.agentAuthorDefinitionId),\n );\n if (agents.length === 0) {\n return [];\n }\n const mentioned = new Set(message.mentionedParticipantIds);\n const mayPrompt = message.hopDepth < MAX_AGENT_HOP_DEPTH;\n const promptDelivery = mayPrompt ? Delivery.Prompt : Delivery.Observe;\n\n if (conversation.kind === ConversationKind.Direct) {\n return agents.map((agent) => ({ participantId: agent.id, delivery: promptDelivery }));\n }\n\n const anyAgentMentioned = agents.some((agent) => mentioned.has(agent.id));\n const defaultAgent = effectiveDefaultAgent(participants);\n return agents.flatMap((agent): RouteDecisionIface[] => {\n if (mentioned.has(agent.id)) {\n return [{ participantId: agent.id, delivery: promptDelivery }];\n }\n if (agent.routingMode === RoutingMode.Mention || agent.routingMode == null) {\n return [];\n }\n if (!anyAgentMentioned && agent.id === defaultAgent?.id) {\n return [{ participantId: agent.id, delivery: promptDelivery }];\n }\n return [{ participantId: agent.id, delivery: Delivery.Observe }];\n });\n};\n\nexport const routeToParticipant =\n (participantId: string) =>\n (args: RouteArgsIface): RouteDecisionIface[] =>\n args.participants.some(\n (participant) =>\n participant.id === participantId &&\n participant.kind === ParticipantKind.Agent &&\n !participant.left,\n )\n ? [{ participantId, delivery: Delivery.Prompt }]\n : [];\n"],
5
5
  "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAKA,MAAM,sBAAsB;AAEnC,MAAM,eAAe,CAAC,iBACpB,aAAa;AAAA,EACX,CAAC,gBAAgB,YAAY,SAAS,gBAAgB,SAAS,CAAC,YAAY;AAC9E;AAKK,MAAM,wBAAwB,CACnC,iBAC4B;AAC5B,QAAM,SAAS,aAAa,YAAY;AACxC,SACE,OAAO,KAAK,CAAC,UAAU,MAAM,gBAAgB,YAAY,OAAO,KAChE,OAAO,KAAK,CAAC,UAAU,MAAM,gBAAgB,YAAY,GAAG,KAC5D;AAEJ;AAGO,MAAM,eAAe,CAAC,SAA+C;AAC1E,QAAM,EAAE,cAAc,SAAS,aAAa,IAAI;AAChD,QAAM,SAAS,aAAa,YAAY,EAAE;AAAA,IACxC,CAAC,UACC,MAAM,OAAO,QAAQ,wBACpB,QAAQ,2BAA2B,QAClC,MAAM,iBAAiB,QAAQ;AAAA,EACrC;AACA,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,CAAC;AAAA,EACV;AACA,QAAM,YAAY,IAAI,IAAI,QAAQ,uBAAuB;AACzD,QAAM,YAAY,QAAQ,WAAW;AACrC,QAAM,iBAAiB,YAAY,SAAS,SAAS,SAAS;AAE9D,MAAI,aAAa,SAAS,iBAAiB,QAAQ;AACjD,WAAO,OAAO,IAAI,CAAC,WAAW,EAAE,eAAe,MAAM,IAAI,UAAU,eAAe,EAAE;AAAA,EACtF;AAEA,QAAM,oBAAoB,OAAO,KAAK,CAAC,UAAU,UAAU,IAAI,MAAM,EAAE,CAAC;AACxE,QAAM,eAAe,sBAAsB,YAAY;AACvD,SAAO,OAAO,QAAQ,CAAC,UAAgC;AACrD,QAAI,UAAU,IAAI,MAAM,EAAE,GAAG;AAC3B,aAAO,CAAC,EAAE,eAAe,MAAM,IAAI,UAAU,eAAe,CAAC;AAAA,IAC/D;AACA,QAAI,MAAM,gBAAgB,YAAY,WAAW,MAAM,eAAe,MAAM;AAC1E,aAAO,CAAC;AAAA,IACV;AACA,QAAI,CAAC,qBAAqB,MAAM,OAAO,cAAc,IAAI;AACvD,aAAO,CAAC,EAAE,eAAe,MAAM,IAAI,UAAU,eAAe,CAAC;AAAA,IAC/D;AACA,WAAO,CAAC,EAAE,eAAe,MAAM,IAAI,UAAU,SAAS,QAAQ,CAAC;AAAA,EACjE,CAAC;AACH;AAEO,MAAM,qBACX,CAAC,kBACD,CAAC,SACC,KAAK,aAAa;AAAA,EAChB,CAAC,gBACC,YAAY,OAAO,iBACnB,YAAY,SAAS,gBAAgB,SACrC,CAAC,YAAY;AACjB,IACI,CAAC,EAAE,eAAe,UAAU,SAAS,OAAO,CAAC,IAC7C,CAAC;",
6
6
  "names": []
7
7
  }
@@ -4,6 +4,7 @@ export declare const decodeBase64: (value: string) => Uint8Array;
4
4
  export declare const concatBytes: (chunks: readonly Uint8Array[]) => Uint8Array;
5
5
  export declare const collectStream: (stream: ReadableStream<Uint8Array>) => Promise<Uint8Array>;
6
6
  export declare const rechunk: (stream: ReadableStream<Uint8Array>, size: number) => AsyncGenerator<Uint8Array>;
7
+ export declare const splitChunks: (stream: ReadableStream<Uint8Array>, size: number) => AsyncGenerator<Uint8Array>;
7
8
  export declare const errorMessage: (cause: unknown) => string;
8
9
  export declare const isNotFoundMessage: (message: string) => boolean;
9
10
  export declare const sleep: (ms: number, signal?: AbortSignal) => Promise<void>;
@@ -50,6 +50,11 @@ const rechunk = async function* (stream, size) {
50
50
  }
51
51
  if (pendingBytes > 0) yield concatBytes(pending);
52
52
  };
53
+ const splitChunks = async function* (stream, size) {
54
+ for await (const chunk of stream)
55
+ for (let offset = 0; offset < chunk.byteLength; offset += size)
56
+ yield chunk.subarray(offset, offset + size);
57
+ };
53
58
  const errorMessage = (cause) => cause instanceof Error ? cause.message : String(cause);
54
59
  const isNotFoundMessage = (message) => /no such file|not found|does not exist|os error 2\b|ENOENT/i.test(message);
55
60
  const sleep = (ms, signal) => new Promise((resolve, reject) => {
@@ -91,6 +96,7 @@ export {
91
96
  isNotFoundMessage,
92
97
  rechunk,
93
98
  sha256Hex,
94
- sleep
99
+ sleep,
100
+ splitChunks
95
101
  };
96
102
  //# sourceMappingURL=bytes.mjs.map