feat(plugins): expose generic AI and public HTTPS capabilities

This commit is contained in:
tianma-if committed 2026-09-03 16:05:41 +08:00
1 parent 4432f2ea47
commit ee9632038f
28 files changed
+605 -14

No files matched your search

+41
View File
@@ -468,3 +468,44 @@ The first demonstrates note queries, selection replacement, commands, and a cust
- Declared permissions are API capability checks, not a hard sandbox for trusted JavaScript.
- Custom panels open from the unified desktop plugin menu or extension settings and cannot yet be pinned to the main navigation or editor sidebar.
- Secret storage is device-local and does not sync to other devices.
## Generic AI and public network capabilities (unreleased)
Plugins may declare `ai:generate` to use the current workspace's default AI model. These calls take ordinary prompts; source parsing, business workflows and prompts belong to the plugin. Credentials stay in the host.
```ts
const status = await context.ai.status(); // { configured, modelName? }
const result = await context.ai.generate({
system: "Translate the supplied text into English.",
prompt: "用户提供的文本",
maxOutputTokens: 1000,
signal: controller.signal,
});
```
`system` is limited to 8,000 characters, `prompt` to 90,000, output to 5,000 tokens, and generation to 120 seconds. The backend requires an interactive user session, disables these capabilities in public demo mode, and redacts provider errors. Each workspace has up to four concurrent calls per AI/network group per app instance; this is not a distributed quota. Model charges follow the configured provider. Plugin deactivation aborts outstanding calls.
Existing `network.fetch(url, init)` remains browser fetch with CORS and omitted credentials. Add both `network` and `network:public`, declare `networkHosts`, and explicitly select `transport: "public"` to use the generic public Internet transport:
```json
{
"permissions": ["network", "network:public"],
"networkHosts": ["example.org"]
}
```
```ts
const response = await context.network.fetch("https://example.org/feed.xml", {
transport: "public",
headers: { Accept: "application/rss+xml" },
redirect: "manual",
signal: controller.signal,
});
const feed = await response.text(); // Parse inside the plugin.
```
Public mode supports HTTPS GET/HEAD on port 443, no request body or credentials, a 20-second deadline, and at most 2,000,000 decoded response bytes. It always returns redirects without following them (`redirect: "error"` rejects them). Upstream 403/429 remain upstream status codes; this transport does not bypass platform restrictions. Allowed request headers: Accept, Accept-Language, If-None-Match, If-Modified-Since, Range. Only content/cache metadata, Location and Retry-After are returned; Set-Cookie is excluded. The response is buffered within the size limit, not an unlimited streaming proxy.
Web and desktop clients use the same authenticated backend transport. Cloudflare uses default workerd public-only Internet egress and no private-service bindings. Self-hosted Bun uses a TLS lookup callback which validates DNS answers and connects directly to those answers; private, special-use and mixed public/private answers are rejected. Synthetic VPN/fake-IP DNS answers in private or reserved ranges are also rejected; do not disable this check. Nonstandard workerd deployments must preserve public-only global egress.
Plugin permission/domain checks run in the trusted client host. Backend routes independently require user authentication and enforce public-only egress; they do not trust client-supplied plugin IDs or allowlists, and do not claim server-attested per-plugin isolation. The trusted-JavaScript limitation still applies. The backend never receives a source enum, search window, evidence schema or report workflow.