Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/bright-messages-connect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"eve": patch
"@vercel/eve-catalog": patch
---

Add guided Photon setup through `eve add channel/photon`, including project creation, phone registration, Vercel Connect or portable credentials, and channel scaffolding.
5 changes: 5 additions & 0 deletions .changeset/calm-photons-queue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eve": patch
---

Queue overlapping Photon messages instead of dropping them, and ignore inbound iMessage events that contain no model-visible content.
69 changes: 17 additions & 52 deletions apps/docs/lib/integrations/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ const channelPresentations: Record<string, ChannelPresentation> = {
logo: "slack",
docsHref: "/docs/channels/slack",
keywords: ["chat", "messaging", "bot", "webhook"],
install: `The eve CLI scaffolds the channel for you. \`eve channels add slack\` writes \`agent/channels/slack.ts\`, adds \`@vercel/connect\`, and runs the Connect setup flow:
install: `The eve CLI scaffolds the channel for you. \`eve add channel/slack\` writes \`agent/channels/slack.ts\`, adds \`@vercel/connect\`, and runs the Connect setup flow:

\`\`\`bash
eve channels add slack
eve add channel/slack
\`\`\`

To wire it up by hand instead, install the framework and the Connect SDK. Slack channels use [Vercel Connect](https://vercel.com/docs/connect) for both the outbound bot token and inbound webhook verification:
Expand Down Expand Up @@ -314,7 +314,7 @@ export default linearChannel({
install: `The eve CLI scaffolds the full Next.js web chat app alongside \`agent/channels/eve.ts\`:

\`\`\`bash
eve channels add web
eve add channel/web
\`\`\`

To wire it up by hand instead, install the framework:
Expand Down Expand Up @@ -842,64 +842,29 @@ export default channel;
See the [Kapso adapter documentation](https://chat-sdk.dev/adapters/vendor-official/kapso) for supported events, capabilities, and credentials.`,
configure: `Connect a WhatsApp number in Kapso, set \`KAPSO_API_KEY\`, \`KAPSO_PHONE_NUMBER_ID\`, and \`KAPSO_WEBHOOK_SECRET\`, then point the Kapso webhook at \`/eve/v1/kapso\`. Use this provider-managed option when you do not want to integrate directly with the WhatsApp Cloud API. See the [Chat SDK channel docs](/docs/channels/chat-sdk) for eve session dispatch, state, streaming, and human-in-the-loop behavior.`,
},
"chat-sdk-photon": {
photon: {
logo: "photon",
docsHref: "/docs/channels/chat-sdk",
badge: "Provider official",
keywords: [
"chat sdk",
"imessage",
"apple messages",
"sms",
"mms",
"rcs",
"photon",
"sendblue",
"linq",
"agentphone",
"dial",
],
install: `Add this Chat SDK channel from eve's registry. This writes \`agent/channels/imessage.ts\` and installs Chat SDK and its adapter dependencies:
docsHref: "/docs/channels/photon",
badge: "First-party",
keywords: ["imessage", "apple messages", "photon", "sms", "phone"],
install: `Add Photon from eve's registry, then follow the guided project, phone, and deployment setup:

\`\`\`bash
eve add channel/chat-sdk-photon
eve add channel/photon
\`\`\``,
quickStart: `Create \`agent/channels/imessage.ts\`:
quickStart: `Create \`agent/channels/photon.ts\`:

\`\`\`ts
// agent/channels/imessage.ts
import { createiMessageAdapter } from "@photon-ai/chat-adapter-imessage";
import { createMemoryState } from "@chat-adapter/state-memory";
import type { Message, Thread } from "chat";
import { chatSdkChannel } from "eve/channels/chat-sdk";
import { connectPhotonCredentials } from "@vercel/connect/eve";
import { photonChannel } from "eve/channels/photon";

export const { bot, channel, send } = chatSdkChannel({
userName: "My Agent",
adapters: {
imessage: createiMessageAdapter({
local: false,
projectId: process.env.IMESSAGE_PROJECT_ID,
projectSecret: process.env.IMESSAGE_PROJECT_SECRET,
}),
},
state: createMemoryState(),
export default photonChannel({
credentials: connectPhotonCredentials(process.env.PHOTON_CONNECTOR_ID!),
});

bot.onNewMention(async (thread: Thread, message: Message) => {
await thread.subscribe();
await send(message.text, { thread });
});

bot.onSubscribedMessage(async (thread: Thread, message: Message) => {
await send(message.text, { thread });
});

export default channel;
\`\`\`

See the [Photon adapter documentation](https://chat-sdk.dev/adapters/vendor-official/photon) for all supported events and credentials.`,
configure: `Set \`IMESSAGE_PROJECT_ID\` and \`IMESSAGE_PROJECT_SECRET\`, then point Photon’s signed webhook at \`/eve/v1/imessage\`. Photon supports cloud, self-hosted, and local macOS deployments. See the [Chat SDK channel docs](/docs/channels/chat-sdk) for eve session dispatch, state, streaming, and human-in-the-loop behavior.`,
\`\`\``,
configure: `The guided setup can create a dedicated Photon project or use existing credentials, register your phone, and choose Vercel Connect or portable environment credentials. Connect-backed setup creates a native Photon connector and routes verified triggers to \`/eve/v1/photon\`; portable setup registers a signed Photon webhook directly.`,
},

"chat-sdk-dial": {
logo: "dial",
docsHref: "/docs/channels/chat-sdk",
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/lib/integrations/discovery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe("integration discovery", () => {
const markdown = integrationMarkdown(slack!);
expect(markdown).toContain("## Install");
expect(markdown).toContain("## Quick start");
expect(markdown).toContain("eve channels add slack");
expect(markdown).toContain("eve add channel/slack");
});

it("renders the Browserbase extension setup", () => {
Expand Down
19 changes: 19 additions & 0 deletions apps/docs/public/r/channel/photon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "channel/photon",
"type": "registry:item",
"title": "Photon",
"description": "Connect an eve agent to iMessage through Photon with guided project and phone setup.",
"dependencies": ["@vercel/connect@0.5.0"],
"meta": {
"eve": {
"setup": {
"command": "eve",
"package": "eve",
"bin": "eve",
"args": ["integration", "setup", "photon"]
},
"requires": ">=0.27.11"
}
}
}
26 changes: 13 additions & 13 deletions apps/docs/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -1209,22 +1209,22 @@
]
},
{
"name": "channel/chat-sdk-photon",
"name": "channel/photon",
"type": "registry:item",
"title": "Photon",
"description": "Cloud, self-hosted, and local iMessage messaging through Photon.",
"dependencies": ["chat", "@photon-ai/chat-adapter-imessage", "@chat-adapter/state-memory"],
"envVars": {
"IMESSAGE_PROJECT_ID": "",
"IMESSAGE_PROJECT_SECRET": ""
},
"files": [
{
"path": "registry/channels/chat-sdk-photon.ts",
"type": "registry:file",
"target": "agent/channels/imessage.ts"
"description": "Connect an eve agent to iMessage through Photon with guided project and phone setup.",
"dependencies": ["@vercel/connect@0.5.0"],
"meta": {
"eve": {
"setup": {
"command": "eve",
"package": "eve",
"bin": "eve",
"args": ["integration", "setup", "photon"]
},
"requires": ">=0.27.11"
}
]
}
},
{
"name": "channel/chat-sdk-dial",
Expand Down
27 changes: 0 additions & 27 deletions apps/docs/registry/channels/chat-sdk-photon.ts

This file was deleted.

4 changes: 1 addition & 3 deletions apps/docs/scripts/validate-channel-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const adapterDependenciesByCatalogSlug: Readonly<Record<string, string>> = {
"chat-sdk-liveblocks": "@liveblocks/chat-sdk-adapter",
"chat-sdk-linq": "@linqapp/chat-sdk-adapter",
"chat-sdk-kapso": "@kapso/chat-adapter",
"chat-sdk-photon": "@photon-ai/chat-adapter-imessage",
"chat-sdk-dial": "@getdial/chat-sdk-adapter",
"chat-sdk-agentphone": "@agentphone/chat-sdk-adapter",
"chat-sdk-lark": "@larksuite/vercel-chat-adapter",
Expand All @@ -65,7 +64,6 @@ const targetSlugsByCatalogSlug: Readonly<Record<string, string>> = {
"chat-sdk-liveblocks": "liveblocks",
"chat-sdk-linq": "linq",
"chat-sdk-kapso": "kapso",
"chat-sdk-photon": "imessage",
"chat-sdk-dial": "dial",
"chat-sdk-agentphone": "agentphone",
"chat-sdk-lark": "lark",
Expand Down Expand Up @@ -106,7 +104,7 @@ for (const [index, item] of items.entries()) {
if (entry === undefined) throw new Error(`Unexpected channel registry item "${item.name}".`);
const registrySlug = expectedSlugs[index];

if (entry.slug === "slack" || entry.slug === "eve") {
if (entry.slug === "slack" || entry.slug === "eve" || entry.slug === "photon") {
const expectedArgs = ["integration", "setup", registrySlug];
if (
setup?.command !== "eve" ||
Expand Down
2 changes: 1 addition & 1 deletion docs/channels/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ agent/
intake.ts
```

Install a built-in channel with `eve add channel/slack` or `eve add channel/web`. You can also author the file by hand.
Install a channel from the registry with `eve add channel/photon`, `eve add channel/slack`, or `eve add channel/web`. You can also author the file by hand.

## The eve HTTP channel (default)

Expand Down
45 changes: 40 additions & 5 deletions docs/channels/photon.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ description: Connect an eve agent to iMessage through Photon.
---

Use `photonChannel` to receive and reply to iMessages through a Photon project.
With Vercel Connect, the channel resolves credentials lazily when the adapter
first initializes:

Run `eve add channel/photon` to create or use a Photon project and register
your phone number. It then asks whether to configure Vercel Connect or portable
credentials. With Vercel Connect, eve creates the connector and configures
Photon’s webhook through Connect. The channel resolves credentials lazily when
the adapter first initializes:

```ts title="agent/channels/photon.ts"
import { connectPhotonCredentials } from "@vercel/connect/eve";
Expand Down Expand Up @@ -37,6 +41,37 @@ export default photonChannel({
```

Set `route` to override the webhook path or `webhookVerifier` to use a different
trusted-forwarder verifier. For direct Photon webhooks, pass `webhookSecret` or
set `IMESSAGE_WEBHOOK_SECRET`; the signing secret takes precedence over the
default OIDC verifier.
trusted-forwarder verifier.

## Other hosts

For a host without Vercel Connect, choose **Use portable credentials** during
`eve add channel/photon`. eve scaffolds the channel and writes
`IMESSAGE_PROJECT_ID` and `IMESSAGE_PROJECT_SECRET` to `.env.local`.

After deploying the agent:

1. Create a Photon webhook for your public `https://…/eve/v1/photon` URL.
2. Copy its signing secret into `IMESSAGE_WEBHOOK_SECRET`.
3. Set `IMESSAGE_PROJECT_ID`, `IMESSAGE_PROJECT_SECRET`, and
`IMESSAGE_WEBHOOK_SECRET` in the host’s encrypted environment variables.

To configure the channel by hand, use lazy environment-backed credentials:

```ts title="agent/channels/photon.ts"
import { photonChannel } from "eve/channels/photon";

export default photonChannel({
async credentials() {
const projectId = process.env.IMESSAGE_PROJECT_ID;
const projectSecret = process.env.IMESSAGE_PROJECT_SECRET;
if (!projectId || !projectSecret) throw new Error("Photon project credentials are required.");
return { projectId, projectSecret };
},
webhookSecret: process.env.IMESSAGE_WEBHOOK_SECRET,
});
```

For direct Photon webhooks, pass `webhookSecret` or set
`IMESSAGE_WEBHOOK_SECRET`; the signing secret takes precedence over the default
OIDC verifier.
10 changes: 2 additions & 8 deletions packages/eve-catalog/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,6 @@ export function connectionProtocols(connection: ConnectionIdentity): ConnectionP
* The canonical set of eve integrations. Order is display order. Each entry
* carries only shared identity; the scaffolder and docs overlay their own
* surface-specific data keyed by {@link IntegrationEntry.slug}.
*
* `surfaces.scaffoldable` reflects what eve's interactive setup flow can
* provision and scaffold today: Slack and Web Chat for channels, plus its
* curated connections. Registry installation is independent of this flag.
* The remaining channels are runtime modules configured by hand, so they
* appear in the gallery but not the setup picker.
*/
export const INTEGRATIONS: readonly IntegrationEntry[] = [
{
Expand Down Expand Up @@ -223,10 +217,10 @@ export const INTEGRATIONS: readonly IntegrationEntry[] = [
surfaces: { scaffoldable: false, gallery: true },
},
{
slug: "chat-sdk-photon",
slug: "photon",
name: "Photon",
kind: "channel",
tagline: "Cloud, self-hosted, and local iMessage messaging through Photon.",
tagline: "iMessage through Photon, with guided project and phone setup.",
surfaces: { scaffoldable: false, gallery: true },
},
{
Expand Down
Loading
Loading