mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-06 04:23:15 -05:00
feat(addons): wire the Discord add-on into packaging, catalog and docs
List the add-on in the package workflow matrix, the package checks, the host operation policy, the catalog template and index, the case inventories of the contract and packaging suites, and the architecture guard (two links to the project community server are not the add-on). Document the connector in the chats guide. Assisted-by: Claude:claude-sonnet-5-5 go
This commit is contained in:
15 files changed
+236
-22
No files matched your search
@@ -2,7 +2,7 @@
|
||||
name: 'add-on packages'
|
||||
|
||||
# Builds, checks, signs and publishes the first-party add-on OCI packages
|
||||
# (Tables, Voice, Face, Fine-tuning, Quantization, Studio, Talk, Telegram, Slack, Office and
|
||||
# (Tables, Voice, Face, Fine-tuning, Quantization, Studio, Talk, Telegram, Slack, Discord, Office and
|
||||
# Sandbox). This workflow is
|
||||
# independent of the backend image workflows: it has its own registry input,
|
||||
# its own signer identity and its own jobs.
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
addon: [tables, voice, face, fine-tuning, quantization, studio, talk, telegram, slack, github, jellyfin, office, sandbox, web, memory]
|
||||
addon: [tables, voice, face, fine-tuning, quantization, studio, talk, telegram, slack, discord, github, jellyfin, office, sandbox, web, memory]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
@@ -236,7 +236,7 @@ jobs:
|
||||
# event it fails the plan. A missing or malformed platform file, or
|
||||
# any other error, fails the plan on every event.
|
||||
include='[]'
|
||||
for id in tables voice face fine-tuning quantization studio talk telegram slack github jellyfin office sandbox web memory; do
|
||||
for id in tables voice face fine-tuning quantization studio talk telegram slack discord github jellyfin office sandbox web memory; do
|
||||
cfg="addons/$id/package/platforms.yaml"
|
||||
err="matrix-$id.err"
|
||||
if rows=$(go run ./scripts/addons/cmd/addonpkg matrix --config "$cfg" 2>"$err"); then
|
||||
|
||||
@@ -92,7 +92,7 @@ var _ = Describe("official library index", func() {
|
||||
Expect(versionPattern.MatchString(r.Version)).To(BeTrue(), r.ID)
|
||||
Expect(r.Artifact).To(HavePrefix("oci://"), r.ID)
|
||||
}
|
||||
Expect(slices.Compact(slices.Sorted(slices.Values(ids)))).To(ConsistOf("fine-tuning", "quantization", "voice", "face", "studio", "talk", "telegram", "slack", "github", "jellyfin", "tables", "office", "sandbox", "web", "memory"))
|
||||
Expect(slices.Compact(slices.Sorted(slices.Values(ids)))).To(ConsistOf("fine-tuning", "quantization", "voice", "face", "studio", "talk", "telegram", "slack", "discord", "github", "jellyfin", "tables", "office", "sandbox", "web", "memory"))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@ var allowed = []entry{
|
||||
{"docs/content/reference/cli-reference.md", "(Telegram, Slack)", "help text that gives chat platforms as examples"},
|
||||
{"docs/content/getting-started/_index.en.md", "Telegram", "a chat platform as an example of where an agent can answer"},
|
||||
{"docs/content/getting-started/first-agent.md", "Telegram", "a chat platform as an example of where an agent can answer"},
|
||||
{"docs/content/reference/ai-coding-assistants.md", "Discord channel", "the project community server, not the add-on"},
|
||||
{"docs/content/getting-started/troubleshooting.md", "LocalAI Discord", "the project community server, not the add-on"},
|
||||
|
||||
// Ordinary words that equal an id or a title.
|
||||
{"core/schema/chats.go", `example:"Sandbox"`, "a sample value in the API documentation"},
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"office": ["workspace."],
|
||||
"web": ["workspace."],
|
||||
"telegram": ["connector."],
|
||||
"slack": ["connector."]
|
||||
"slack": ["connector."],
|
||||
"discord": ["connector."]
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ LocalAI provides a comprehensive set of features for running AI models locally.
|
||||
- **[Chats]({{% relref "features/chats" %}})** - Conversations the server keeps, with files, sub-agents, skills and add-on tools.
|
||||
- **[Saved agents, triggers and inbox]({{% relref "features/chats-agents" %}})** - Instructions and exact tool grants, schedules, and notifications.
|
||||
- **[Collections]({{% relref "features/collections" %}})** - The knowledge base: upload documents and search them by meaning.
|
||||
- **[Telegram and Slack connectors]({{% relref "features/chats-connectors" %}})** - Talk to an agent from Telegram or Slack.
|
||||
- **[Telegram, Slack and Discord connectors]({{% relref "features/chats-connectors" %}})** - Talk to an agent from Telegram, Slack or Discord.
|
||||
- **[Moving from the old chat and agents]({{% relref "features/chats-migration" %}})** - What was converted and what was dropped.
|
||||
- **[Model Context Protocol (MCP)]({{% relref "features/mcp" %}})** - Give a model external tools over MCP.
|
||||
- **[LocalAI Assistant]({{% relref "features/localai-assistant" %}})** - Chat to administer your LocalAI instance.
|
||||
|
||||
@@ -700,7 +700,7 @@ The three roles split the work of a LocalAI process as follows.
|
||||
| The carrier | Loopback, with keys made at each start | Served on the network | Client only |
|
||||
| Chat turns | Yes | No | Yes |
|
||||
| Model loading | In this process, or on workers in distributed mode | No models. In distributed mode it routes loads to workers. | In this process, or on workers in distributed mode |
|
||||
| Connector polling (Telegram, Slack) | Yes | No | Yes, on the one leader frontend |
|
||||
| Connector polling (Telegram, Slack, Discord) | Yes | No | Yes, on the one leader frontend |
|
||||
| Triggers, loops and agent jobs | Yes | No | Yes |
|
||||
| API and UI for users | Yes | No. Send users to a frontend. | Yes |
|
||||
|
||||
@@ -2451,7 +2451,7 @@ The owner process holds everything about host grants. A frontend stores nothing
|
||||
## Connector add-ons
|
||||
|
||||
A connector add-on carries the messages of a messaging platform between the platform
|
||||
and the [chats](/features/chats-connectors/). The Telegram and Slack add-ons are
|
||||
and the [chats](/features/chats-connectors/). The Telegram, Slack and Discord add-ons are
|
||||
first-party connector add-ons. The host keeps what is the same for every platform (the
|
||||
bindings, the sealed bot token, the allowlist, the sender log, one chat for each sender
|
||||
or thread, the turn and its notifications), so an add-on holds only the transport and
|
||||
|
||||
@@ -7,7 +7,7 @@ url = "/features/chats-connectors/"
|
||||
|
||||
The Connectors page of the [chats](/features/chats/) (`/app/chats/connectors`, under **Agents** in the sidebar) lists the messaging bindings you made, and the MCP servers have a page of their own (**MCP connectors** in the sidebar, `/app/mcp-connectors`):
|
||||
|
||||
- A **messaging connector** binds a bot of a platform to one of your agents, so a person can talk to it from that platform. The platform comes from a **connector add-on**: the [Telegram add-on](#telegram) or the [Slack add-on](#slack) (the [GitHub add-on](#github) and the [Jellyfin add-on](#jellyfin) hold a token for your agents instead of carrying messages). This is the first half of this page.
|
||||
- A **messaging connector** binds a bot of a platform to one of your agents, so a person can talk to it from that platform. The platform comes from a **connector add-on**: the [Telegram add-on](#telegram), the [Slack add-on](#slack) or the [Discord add-on](#discord) (the [GitHub add-on](#github) and the [Jellyfin add-on](#jellyfin) hold a token for your agents instead of carrying messages). This is the first half of this page.
|
||||
- An **MCP server** gives your chats and agents more tools. See [MCP servers](#mcp-servers).
|
||||
|
||||
## Connector add-ons
|
||||
@@ -34,7 +34,7 @@ add-on"; nothing polls and nothing is lost.
|
||||
|
||||
Each kind in the add-on manifest declares `delivery`:
|
||||
|
||||
- **`pull`** (Slack and Telegram). The host polls the add-on. One process in the
|
||||
- **`pull`** (Slack, Discord and Telegram). The host polls the add-on. One process in the
|
||||
cluster, the leader, does the polling. It stores the offset with the binding. When
|
||||
the leader stops, a new leader continues from that offset.
|
||||
- **`push`**. The add-on calls the host operation `connector.inbound` for each
|
||||
@@ -303,6 +303,120 @@ Slack counterpart).
|
||||
The Events API over HTTP is not supported: it needs a public address, and Socket Mode
|
||||
gives the same events without one.
|
||||
|
||||
## Discord
|
||||
|
||||
The Discord add-on binds a Discord bot to one of your [saved agents](/features/chats-agents/).
|
||||
People talk to the agent in a direct message with the bot, or by mentioning the bot in a
|
||||
channel or thread of a server. The add-on keeps a Gateway link (a websocket that the
|
||||
add-on opens to Discord), so LocalAI needs no public address.
|
||||
|
||||
### Set up a binding
|
||||
|
||||
1. Install the **Discord** add-on from the add-on gallery.
|
||||
2. At `discord.com/developers/applications` choose **New Application**. On the **Bot**
|
||||
page choose **Reset Token** and copy the token once.
|
||||
3. On the same page, under **Privileged Gateway Intents**, turn on **Message Content
|
||||
Intent**. Without it Discord sends no text from servers. The add-on needs no other
|
||||
privileged intent. The page **Test** shows a warning when the intent is off.
|
||||
4. Add the bot to a server with the link that the add-on page builds under **How to make
|
||||
the Discord bot**: type the Application ID and open the link. It uses the scope
|
||||
`bot` and the permission number `274878008320`: View Channels, Send Messages,
|
||||
Send Messages in Threads, Attach Files and Read Message History. Never give the bot
|
||||
Administrator, Manage Messages or Mention Everyone.
|
||||
5. On the Discord add-on page make a binding: a name, the token, the agent, and who may use
|
||||
it. When you save, LocalAI checks the token and shows which bot it belongs to.
|
||||
6. Mention the bot in a channel it can see, or write to it in a direct message.
|
||||
|
||||
```
|
||||
curl -X POST .../api/chats/connectors -d '{"kind": "discord", "name": "Team bot", "token": "<bot token>", "agent_id": "<id>", "enabled": true, "allow": ["<user ID>", "<channel ID>"]}'
|
||||
```
|
||||
|
||||
### How Discord messages map to chats
|
||||
|
||||
- **A direct message** with the bot is a conversation with its sender. The host answers it
|
||||
only for a listed person, or when the binding accepts anyone (a person can write to a bot
|
||||
only when they share a server with it).
|
||||
- **A mention** of the bot in a server channel, or a reply to a message of the bot, addresses
|
||||
the bot. The answer goes in the same channel. Any other channel message is not read.
|
||||
`@everyone`, `@here` and role mentions never address the bot.
|
||||
- **A thread** (also a forum post) is a chat of its own, and its chat is the parent channel,
|
||||
so listing a channel also covers its threads. The bot follows a thread once it was
|
||||
mentioned in it: later messages of the thread need no new mention. The setting **Threads
|
||||
the bot follows** (`followThreads`) is `mentioned` (the default) or `never`. A followed
|
||||
thread stays followed for 24 hours after its last message; the add-on keeps the list in
|
||||
its data directory (channel and thread IDs and times, never a token). The bot does not
|
||||
start threads.
|
||||
- **Earlier messages of a thread** are read once when a thread chat starts (see
|
||||
[Earlier messages of a thread](#earlier-messages-of-a-thread)): at most 30, through
|
||||
`GET /channels/{thread}/messages`, which allows 100 per call. Messages of other bots and of
|
||||
Discord itself (joins, pins) are left out. This needs Read Message History.
|
||||
- **Never answered**: every message that a bot or a webhook wrote, the messages of the bot
|
||||
itself, and system messages. Two bots cannot answer each other.
|
||||
- **Answers** are plain Markdown (Discord reads it) and split at 2,000 characters, the limit
|
||||
of Discord, with code blocks closed and opened again at each cut. Every message carries
|
||||
`allowed_mentions: {"parse": []}`, and the add-on also breaks up `@everyone`, `@here` and
|
||||
`<@...>` mentions in the text, so the answer can never ping anyone. The bot sets no typing
|
||||
indicator (Discord discourages it for bots); a working message (see
|
||||
[How the bot answers](#how-the-bot-answers)) shows that the agent works. Edits are limited
|
||||
by Discord, so a live answer updates about once a second.
|
||||
- **Files.** A file attached to a message (at most 8, 10 MB each) is downloaded from the
|
||||
Discord CDN, with a fresh link read at the moment of the download and without the token,
|
||||
and attached to the chat. A file that the agent makes is uploaded (10 MB at most).
|
||||
- **Waits.** When Discord answers `429`, the add-on waits the time it asks for (the
|
||||
`Retry-After` header, else `retry_after` of the body) once and tries again. An edit is
|
||||
not repeated.
|
||||
- **Start a new chat** with `!new`. Discord clients may take a message that starts with a
|
||||
slash for one of their own commands, so `!new` is the documented form (see
|
||||
[Start a new chat with `/new`](#start-a-new-chat-with-new)). The add-on has no slash
|
||||
commands.
|
||||
|
||||
### Who may use the bot
|
||||
|
||||
The binding has one list of Discord IDs (numbers; turn on Developer Mode in Discord, then
|
||||
right-click and choose Copy ID):
|
||||
|
||||
- **A user ID**: the person may use the bot in a direct message and by mentioning it in any
|
||||
channel the bot reads. The person is a listed sender, so they hold every capability of the
|
||||
binding that is not sensitive.
|
||||
- **A channel ID**: everyone in the channel (and its threads) may mention the bot there.
|
||||
They get no capability of their own (see
|
||||
[Capabilities, roles and pairing](#capabilities-roles-and-pairing)).
|
||||
- **No names and no server IDs.** The page accepts IDs only: names are not unique and
|
||||
change hands. A server (guild) ID matches nothing, because the chat of a message is a
|
||||
channel; use the channel IDs. The page names every entry that is not an ID. The add-on
|
||||
cannot see the allowlist, so a guild ID that is saved over the API is not refused: it is
|
||||
only inert.
|
||||
|
||||
**Anyone** (`accept_any`) is for public channels and read-only agents. Anyone who can message
|
||||
the bot, or mention it in a channel it can read, is let in. The host gives these senders
|
||||
**no capability** (only listed or paired senders hold one), so the agent cannot save memory,
|
||||
propose triggers or take their files for them. The agent's own tools still work for them:
|
||||
give the agent read-only tools for this connection. Text from a public channel is untrusted
|
||||
and can try to steer the agent (prompt injection). The host limits each sender to 20 messages
|
||||
a minute, and the add-on queues at most 30 messages a minute of one sender, so one person
|
||||
cannot fill the queue of the link. Roles of a server are not mapped: the add-on declares no
|
||||
role, because a server administrator is not a role ID and the permission check would need
|
||||
each member's roles and each channel's overwrites.
|
||||
|
||||
### Notifications in Discord
|
||||
|
||||
Set a channel ID as the notification chat to post them there, or `user:` followed by your
|
||||
user ID to receive them as direct messages from the bot.
|
||||
|
||||
### The token of a bot
|
||||
|
||||
The token is sealed like the token of a Telegram bot, and no API returns it. The add-on holds
|
||||
it in memory while it keeps the Gateway link of the binding open, writes it nowhere and calls
|
||||
only `discord.com`, the Gateway and the Discord CDN. The link is closed after two minutes
|
||||
without a poll (the binding was switched off or deleted).
|
||||
|
||||
A binding is switched off, with a notification, when Discord refuses the token (HTTP 401, or
|
||||
Gateway close code 4004) or the intents (4013, 4014: the Message Content Intent is off). The
|
||||
link reconnects with a backoff after any other failure and resumes the session, so events
|
||||
are not lost across a short break. Discord allows 1,000 identifies a day for a bot, so the
|
||||
add-on never retries a refused token. Use one LocalAI instance for one bot: a second process
|
||||
that uses the same token would receive the same events and answer twice.
|
||||
|
||||
## What a message gets
|
||||
|
||||
- **The agent's tools only.** A message gets exactly the tools the agent grants,
|
||||
@@ -479,7 +593,7 @@ declares for its platform, the limit of the platform (the host ceiling that the
|
||||
administrator sets) and the limit that you set for the bot. The agent reads the same
|
||||
number in its instructions, so it does not promise a file that cannot go.
|
||||
|
||||
An add-on that streams files (Slack and Telegram do) has no inline cap: a file moves in
|
||||
An add-on that streams files (Slack, Discord and Telegram do) has no inline cap: a file moves in
|
||||
chunks, by a short-lived handle, so a 6 MB PDF goes both ways. An add-on that does not
|
||||
stream keeps the inline cap of 1 MiB, whatever you set, and the sentence says "limit of
|
||||
this add-on version".
|
||||
@@ -489,6 +603,7 @@ What the platforms allow, from their own documentation:
|
||||
| Platform | Bot reads a file | Bot sends a file |
|
||||
|---|---|---|
|
||||
| Slack | No separate bot limit is documented. The add-on declares the 1 GB per file that a member can add ([Add files to Slack](https://slack.com/help/articles/201330736-Add-files-to-Slack)); the [upload API](https://docs.slack.dev/reference/methods/files.getUploadURLExternal) states none either. | 1 GB per file, by the external upload flow. |
|
||||
| Discord | 10 MB: the add-on declares a limit that fits every server level; Discord states the limit per server and per person, and a bot may be allowed less. | 10 MB, as one attachment of a message. |
|
||||
| Telegram | 20 MB with `getFile` on the public Bot API ([Bots FAQ](https://core.telegram.org/bots/faq)). | 50 MB for a document, 10 MB for a photo; a larger picture goes as a document ([Bots FAQ](https://core.telegram.org/bots/faq)). |
|
||||
|
||||
A local Bot API server lifts the Telegram limits (no download limit, 2000 MB upload,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
This directory holds the template of the catalog entries of the first-party add-ons.
|
||||
It holds no live URL, registry or namespace. The registry and repository are inputs of
|
||||
the release workflow (`ADDON_OCI_REPOSITORY`). Each first-party add-on has its own
|
||||
template (`tables`, `voice`, `face`, `fine-tuning`, `quantization`, `studio`, `talk`, `office`, `sandbox`, `web`, `memory`, `github`, `jellyfin`) and its own release
|
||||
template (`tables`, `voice`, `face`, `fine-tuning`, `quantization`, `studio`, `talk`, `office`, `sandbox`, `web`, `memory`, `github`, `jellyfin`, `discord`) and its own release
|
||||
platform matrix, `addons/<id>/package/platforms.yaml`. The templates differ in `name:` only.
|
||||
|
||||
## Generate the index
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
id: "{{addon}}"
|
||||
name: Discord
|
||||
description: "{{description}}"
|
||||
version: "{{version}}"
|
||||
channel: "{{channel}}"
|
||||
artifact: "oci://{{repository}}:{{tag}}"
|
||||
digest: "{{digest}}"
|
||||
os: "{{os}}"
|
||||
arch: "{{arch}}"
|
||||
policy:
|
||||
requireSignature: true
|
||||
issuer: "{{issuer}}"
|
||||
identity: "{{identity}}"
|
||||
ui:
|
||||
title: "{{title}}"
|
||||
description: "{{description}}"
|
||||
mainPage: "{{main_page}}"
|
||||
icon: "{{icon}}"
|
||||
@@ -10,6 +10,78 @@
|
||||
# backend. A tagged release does not read this file for its pins: the release
|
||||
# workflow renders pinned entries into the asset addons-index.yaml of the
|
||||
# release (see .agents/preparing-a-release.md).
|
||||
- id: "discord"
|
||||
name: Discord
|
||||
description: "Bind a Discord bot to one of your saved agents, so people can talk to it from Discord."
|
||||
version: "0.0.0-development"
|
||||
channel: "development"
|
||||
artifact: "oci://quay.io/go-skynet/local-ai-addons:discord-development"
|
||||
mutable: true
|
||||
os: "darwin"
|
||||
arch: "amd64"
|
||||
policy:
|
||||
requireSignature: true
|
||||
issuer: "https://token.actions.githubusercontent.com"
|
||||
identity: "https://github.com/mudler/LocalAI/.github/workflows/addons-package.yml@refs/heads/master"
|
||||
ui:
|
||||
title: "Discord"
|
||||
description: "Bind a Discord bot to one of your saved agents, so people can talk to it from Discord."
|
||||
mainPage: "bots"
|
||||
icon: "ui/icon.png"
|
||||
- id: "discord"
|
||||
name: Discord
|
||||
description: "Bind a Discord bot to one of your saved agents, so people can talk to it from Discord."
|
||||
version: "0.0.0-development"
|
||||
channel: "development"
|
||||
artifact: "oci://quay.io/go-skynet/local-ai-addons:discord-development"
|
||||
mutable: true
|
||||
os: "darwin"
|
||||
arch: "arm64"
|
||||
policy:
|
||||
requireSignature: true
|
||||
issuer: "https://token.actions.githubusercontent.com"
|
||||
identity: "https://github.com/mudler/LocalAI/.github/workflows/addons-package.yml@refs/heads/master"
|
||||
ui:
|
||||
title: "Discord"
|
||||
description: "Bind a Discord bot to one of your saved agents, so people can talk to it from Discord."
|
||||
mainPage: "bots"
|
||||
icon: "ui/icon.png"
|
||||
- id: "discord"
|
||||
name: Discord
|
||||
description: "Bind a Discord bot to one of your saved agents, so people can talk to it from Discord."
|
||||
version: "0.0.0-development"
|
||||
channel: "development"
|
||||
artifact: "oci://quay.io/go-skynet/local-ai-addons:discord-development"
|
||||
mutable: true
|
||||
os: "linux"
|
||||
arch: "amd64"
|
||||
policy:
|
||||
requireSignature: true
|
||||
issuer: "https://token.actions.githubusercontent.com"
|
||||
identity: "https://github.com/mudler/LocalAI/.github/workflows/addons-package.yml@refs/heads/master"
|
||||
ui:
|
||||
title: "Discord"
|
||||
description: "Bind a Discord bot to one of your saved agents, so people can talk to it from Discord."
|
||||
mainPage: "bots"
|
||||
icon: "ui/icon.png"
|
||||
- id: "discord"
|
||||
name: Discord
|
||||
description: "Bind a Discord bot to one of your saved agents, so people can talk to it from Discord."
|
||||
version: "0.0.0-development"
|
||||
channel: "development"
|
||||
artifact: "oci://quay.io/go-skynet/local-ai-addons:discord-development"
|
||||
mutable: true
|
||||
os: "linux"
|
||||
arch: "arm64"
|
||||
policy:
|
||||
requireSignature: true
|
||||
issuer: "https://token.actions.githubusercontent.com"
|
||||
identity: "https://github.com/mudler/LocalAI/.github/workflows/addons-package.yml@refs/heads/master"
|
||||
ui:
|
||||
title: "Discord"
|
||||
description: "Bind a Discord bot to one of your saved agents, so people can talk to it from Discord."
|
||||
mainPage: "bots"
|
||||
icon: "ui/icon.png"
|
||||
- id: "face"
|
||||
name: Face
|
||||
description: "Find out whose face is in a photo, or whether two photos show the same person."
|
||||
|
||||
@@ -18,7 +18,7 @@ var _ = Describe("official host policy deployment", func() {
|
||||
grants, err := config.LoadAddonHostPolicy(filepath.Join(root, "deploy", "addons", "host-policy.json"))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
// Deployment-owned exception: historical identity grants, not core defaults.
|
||||
legacy := "fine-tuning=finetune.,quantization=quantize.,sandbox=workspace.,sandbox=egress.,office=workspace.,web=workspace.,telegram=connector.,slack=connector."
|
||||
legacy := "fine-tuning=finetune.,quantization=quantize.,sandbox=workspace.,sandbox=egress.,office=workspace.,web=workspace.,telegram=connector.,slack=connector.,discord=connector."
|
||||
want, err := config.ParseAddonHostOps(legacy)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(grants).To(Equal(want))
|
||||
|
||||
@@ -31,10 +31,11 @@ var officialRequests = map[string]contract.HostOperations{
|
||||
// file operations are optional. Delivery is pull, so neither add-on calls
|
||||
// connector.inbound.
|
||||
"slack": {Optional: strings.Fields("connector.file.get connector.file.put")},
|
||||
"discord": {Optional: strings.Fields("connector.file.get connector.file.put")},
|
||||
"telegram": {Optional: strings.Fields("connector.file.get connector.file.put")},
|
||||
}
|
||||
|
||||
// connectorRoot holds the file transfer code that slack and telegram share. It
|
||||
// connectorRoot holds the file transfer code that the connector add-ons share. It
|
||||
// names its operations by constant, so the audit reads those too.
|
||||
const connectorRoot = "addons/internal/connector"
|
||||
|
||||
@@ -61,7 +62,7 @@ var _ = Describe("official typed package contracts", func() {
|
||||
// of support; compare independently with the real registered vocabulary.
|
||||
var used []string
|
||||
roots := []string{root}
|
||||
if id == "slack" || id == "telegram" {
|
||||
if id == "slack" || id == "telegram" || id == "discord" {
|
||||
roots = append(roots, filepath.Join("../../..", connectorRoot))
|
||||
}
|
||||
for _, root := range roots {
|
||||
|
||||
@@ -954,7 +954,7 @@ var _ = Describe("catalog template", func() {
|
||||
Expect(err).To(MatchError(ContainSubstring("development channel only")))
|
||||
})
|
||||
It("renders an entry for every first-party add-on from its own template", func() {
|
||||
for _, id := range []string{"tables", "voice", "face", "fine-tuning", "quantization", "studio", "talk", "telegram", "slack", "github", "jellyfin", "office", "sandbox", "web", "memory"} {
|
||||
for _, id := range []string{"tables", "voice", "face", "fine-tuning", "quantization", "studio", "talk", "telegram", "slack", "discord", "github", "jellyfin", "office", "sandbox", "web", "memory"} {
|
||||
p := newProjectFor(id, both)
|
||||
m := p.merged("1.2.3", rev, nil)
|
||||
repoName := newRegistry().repo("addons")
|
||||
@@ -1051,7 +1051,7 @@ var _ = Describe("catalog template", func() {
|
||||
for _, e := range entries {
|
||||
got[e.ID] = e.ToolCount
|
||||
}
|
||||
Expect(got).To(Equal(map[string]int{"tables": 16, "fine-tuning": 8, "quantization": 6, "voice": 0, "face": 0, "studio": 0, "talk": 0, "telegram": 0, "slack": 0, "github": 14, "jellyfin": 16, "office": 11, "sandbox": 5, "web": 5, "memory": 0}))
|
||||
Expect(got).To(Equal(map[string]int{"tables": 16, "fine-tuning": 8, "quantization": 6, "voice": 0, "face": 0, "studio": 0, "talk": 0, "telegram": 0, "slack": 0, "discord": 0, "github": 14, "jellyfin": 16, "office": 11, "sandbox": 5, "web": 5, "memory": 0}))
|
||||
})
|
||||
It("refuses missing inputs, backend repositories, bad channels and unknown placeholders", func() {
|
||||
reg := newRegistry()
|
||||
@@ -1213,7 +1213,7 @@ var _ = Describe("workflow policy", func() {
|
||||
})
|
||||
It("rejects a workflow that names one add-on by path or skips an add-on in the matrix", func() {
|
||||
expect(mutate("node \"addons/$ADDON/ui/build.mjs\"\n - name: Fill", "node addons/tables/ui/build.mjs\n - name: Fill"), "P_ADDON_PATH")
|
||||
expect(mutate(" addon: [tables, voice, face, fine-tuning, quantization, studio, talk, telegram, slack, github, jellyfin, office, sandbox, web, memory]\n", " platform: [x]\n"), "P_MATRIX")
|
||||
expect(mutate(" addon: [tables, voice, face, fine-tuning, quantization, studio, talk, telegram, slack, discord, github, jellyfin, office, sandbox, web, memory]\n", " platform: [x]\n"), "P_MATRIX")
|
||||
})
|
||||
It("rejects a plan that does not refuse an add-on without an enabled platform", func() {
|
||||
expect(mutate("has no enabled platform; refusing to publish", "has no platform"), "P_FAIL_CLOSED")
|
||||
@@ -1263,7 +1263,7 @@ var _ = Describe("workflow policy", func() {
|
||||
|
||||
// firstPartyAddons are the add-ons the release workflow packages. The list is
|
||||
// written out so a new add-on is a deliberate change here and in the workflow.
|
||||
var firstPartyAddons = []string{"tables", "voice", "face", "fine-tuning", "quantization", "studio", "talk", "telegram", "slack", "github", "jellyfin", "office", "sandbox", "web", "memory"}
|
||||
var firstPartyAddons = []string{"tables", "voice", "face", "fine-tuning", "quantization", "studio", "talk", "telegram", "slack", "discord", "github", "jellyfin", "office", "sandbox", "web", "memory"}
|
||||
|
||||
func readWorkflow() string {
|
||||
GinkgoHelper()
|
||||
|
||||
@@ -89,7 +89,7 @@ test -f "$work/voice/receipt.json"
|
||||
case_ok 'package.sh builds and verifies the voice add-on for the host'
|
||||
# A platform other than the host is refused for every add-on, whatever the config.
|
||||
if [ "$host" = linux/amd64 ]; then foreign=linux/arm64; else foreign=linux/amd64; fi
|
||||
for id in tables voice face fine-tuning quantization studio talk telegram slack office sandbox web memory; do
|
||||
for id in tables voice face fine-tuning quantization studio talk telegram slack discord office sandbox web memory; do
|
||||
expect_fail "package.sh refuses a foreign platform without an executable: $id" 'is not this host' sh scripts/addons/package.sh --config "addons/$id/package/platforms.yaml" --layout "$work/foreign-$id" --version 1.2.3 --platform "$foreign" --local-check
|
||||
done
|
||||
case_ok 'package.sh refuses a foreign platform without an executable for every add-on'
|
||||
@@ -123,11 +123,11 @@ mkdir -p "$work/runtime/gvisor-bin"
|
||||
for f in runsc gvisor-profile cloud-hypervisor virtiofsd gvisor-bin/checkpointgofer gvisor-bin/gvisor-sentry-prewarmer gvisor-bin/gvisor_sentry gvisor-bin/runsc-fd-parking gvisor-bin/runsc-metric-server; do
|
||||
printf 'stand-in\n' >"$work/runtime/$f"
|
||||
done
|
||||
for id in tables voice face fine-tuning quantization studio talk telegram slack office sandbox web memory; do
|
||||
for id in tables voice face fine-tuning quantization studio talk telegram slack discord office sandbox web memory; do
|
||||
PATH="$work/stubbin:$PATH" sh scripts/addons/package.sh --config "addons/$id/package/platforms.yaml" --layout "$work/stub-$id" --version 1.2.3 --platform "$host" --runtime-dir "$work/runtime" --local-check >"$work/out" 2>&1 || { cat "$work/out" >&2; exit 1; }
|
||||
done
|
||||
grep -x './addons/tables/cmd/tables CGO_ENABLED=1' "$work/gobuild.log" >/dev/null
|
||||
for id in voice face fine-tuning quantization studio talk telegram slack office sandbox web memory; do
|
||||
for id in voice face fine-tuning quantization studio talk telegram slack discord office sandbox web memory; do
|
||||
grep -x "./addons/$id/cmd/$id CGO_ENABLED=0" "$work/gobuild.log" >/dev/null || { echo "FAIL: $id is not built with CGO_ENABLED=0" >&2; cat "$work/gobuild.log" >&2; exit 1; }
|
||||
done
|
||||
case_ok 'package.sh builds Tables with cgo and the pure Go add-ons without'
|
||||
|
||||
@@ -482,6 +482,7 @@
|
||||
"audits actual host calls and strict package contract for quantization",
|
||||
"audits actual host calls and strict package contract for sandbox",
|
||||
"audits actual host calls and strict package contract for slack",
|
||||
"audits actual host calls and strict package contract for discord",
|
||||
"audits actual host calls and strict package contract for studio",
|
||||
"audits actual host calls and strict package contract for tables",
|
||||
"audits actual host calls and strict package contract for talk",
|
||||
@@ -553,6 +554,7 @@
|
||||
"has consistent package files for quantization",
|
||||
"has consistent package files for sandbox",
|
||||
"has consistent package files for slack",
|
||||
"has consistent package files for discord",
|
||||
"has consistent package files for studio",
|
||||
"has consistent package files for tables",
|
||||
"has consistent package files for talk",
|
||||
@@ -4465,6 +4467,7 @@
|
||||
"package.sh refuses a foreign platform without an executable: talk",
|
||||
"package.sh refuses a foreign platform without an executable: telegram",
|
||||
"package.sh refuses a foreign platform without an executable: slack",
|
||||
"package.sh refuses a foreign platform without an executable: discord",
|
||||
"package.sh refuses a foreign platform without an executable for every add-on",
|
||||
"package.sh builds Tables with cgo and the pure Go add-ons without",
|
||||
"matrix fails closed while no platform is enabled",
|
||||
@@ -4516,6 +4519,7 @@
|
||||
"go: has consistent package files for quantization",
|
||||
"go: has consistent package files for sandbox",
|
||||
"go: has consistent package files for slack",
|
||||
"go: has consistent package files for discord",
|
||||
"go: has consistent package files for studio",
|
||||
"go: has consistent package files for tables",
|
||||
"go: has consistent package files for talk",
|
||||
@@ -4570,6 +4574,7 @@
|
||||
"go: audits actual host calls and strict package contract for quantization",
|
||||
"go: audits actual host calls and strict package contract for sandbox",
|
||||
"go: audits actual host calls and strict package contract for slack",
|
||||
"go: audits actual host calls and strict package contract for discord",
|
||||
"go: audits actual host calls and strict package contract for studio",
|
||||
"go: audits actual host calls and strict package contract for tables",
|
||||
"go: audits actual host calls and strict package contract for talk",
|
||||
|
||||
Reference in new issue
Block a user