mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-27 11:20:42 +01:00
Merge branch 'codex/work-folders-pi-refresh' into codex/work-folders-storybook-refresh
* codex/work-folders-pi-refresh: fix(runner): keep healthy native sessions alive (#13261) feat(connections): add AgentMail inboxes and email tasks (#13256) fix: stop completion reviews caused by policy upgrades (#13266) fix(ci): avoid empty pnpm caches from lockfile refresh (#13267) feat: accept a base64-encoded Cloud UI snippet (#13245) ci: use reserved AWS capacity for post-merge cloud verification (#13257) Fix Codex API key authentication in tests and runs (#13260) refactor: remove automatic productivity reviews (#13263) fix: continue conversations after confirmed remote runner stop (#13254) ci: cache Rust dependencies used by post-merge typecheck (#13259) fix(ui): restore task page archive shortcut (#13253) feat(ui): show one rolling runner activity per commentary group (#13255) fix(ui): hide retry countdown after execution starts (#13258) test: isolate native controller takeover fixture (#13212)
This commit is contained in:
commit
24a7ab22f6
201 files changed
+62608
-3880
No files matched your search
@@ -1,67 +1,68 @@
|
||||
import a0 from "./app-definitions/zapier.json" with { type: "json" };
|
||||
import a1 from "./app-definitions/github.json" with { type: "json" };
|
||||
import a2 from "./app-definitions/slack.json" with { type: "json" };
|
||||
import a3 from "./app-definitions/microsoft-teams.json" with { type: "json" };
|
||||
import a4 from "./app-definitions/telegram.json" with { type: "json" };
|
||||
import a5 from "./app-definitions/discord.json" with { type: "json" };
|
||||
import a6 from "./app-definitions/notion.json" with { type: "json" };
|
||||
import a7 from "./app-definitions/posthog.json" with { type: "json" };
|
||||
import a8 from "./app-definitions/linear.json" with { type: "json" };
|
||||
import a9 from "./app-definitions/context7.json" with { type: "json" };
|
||||
import a10 from "./app-definitions/shopify.json" with { type: "json" };
|
||||
import a11 from "./app-definitions/composio.json" with { type: "json" };
|
||||
import a12 from "./app-definitions/oauth-generic.json" with { type: "json" };
|
||||
import a13 from "./app-definitions/api-key-generic.json" with { type: "json" };
|
||||
import a14 from "./app-definitions/sentry.json" with { type: "json" };
|
||||
import a15 from "./app-definitions/vercel.json" with { type: "json" };
|
||||
import a16 from "./app-definitions/anthropic.json" with { type: "json" };
|
||||
import a17 from "./app-definitions/jira.json" with { type: "json" };
|
||||
import a18 from "./app-definitions/airtable.json" with { type: "json" };
|
||||
import a19 from "./app-definitions/beehiiv.json" with { type: "json" };
|
||||
import a20 from "./app-definitions/bitly.json" with { type: "json" };
|
||||
import a21 from "./app-definitions/candid.json" with { type: "json" };
|
||||
import a22 from "./app-definitions/cloudflare.json" with { type: "json" };
|
||||
import a23 from "./app-definitions/cloudinary.json" with { type: "json" };
|
||||
import a24 from "./app-definitions/coda.json" with { type: "json" };
|
||||
import a25 from "./app-definitions/hugging-face.json" with { type: "json" };
|
||||
import a26 from "./app-definitions/kernel.json" with { type: "json" };
|
||||
import a27 from "./app-definitions/local-falcon.json" with { type: "json" };
|
||||
import a28 from "./app-definitions/make.json" with { type: "json" };
|
||||
import a29 from "./app-definitions/manufact.json" with { type: "json" };
|
||||
import a30 from "./app-definitions/miro.json" with { type: "json" };
|
||||
import a31 from "./app-definitions/netlify.json" with { type: "json" };
|
||||
import a32 from "./app-definitions/oreilly.json" with { type: "json" };
|
||||
import a33 from "./app-definitions/planetscale.json" with { type: "json" };
|
||||
import a34 from "./app-definitions/resend.json" with { type: "json" };
|
||||
import a35 from "./app-definitions/ticktick.json" with { type: "json" };
|
||||
import a36 from "./app-definitions/todoist.json" with { type: "json" };
|
||||
import a37 from "./app-definitions/webflow.json" with { type: "json" };
|
||||
import a38 from "./app-definitions/wix.json" with { type: "json" };
|
||||
import a39 from "./app-definitions/brex.json" with { type: "json" };
|
||||
import a40 from "./app-definitions/clickhouse.json" with { type: "json" };
|
||||
import a41 from "./app-definitions/egnyte.json" with { type: "json" };
|
||||
import a42 from "./app-definitions/embat.json" with { type: "json" };
|
||||
import a43 from "./app-definitions/mixpanel.json" with { type: "json" };
|
||||
import a44 from "./app-definitions/postman.json" with { type: "json" };
|
||||
import a45 from "./app-definitions/razorpay.json" with { type: "json" };
|
||||
import a46 from "./app-definitions/sanity.json" with { type: "json" };
|
||||
import a47 from "./app-definitions/stripe.json" with { type: "json" };
|
||||
import a48 from "./app-definitions/supabase.json" with { type: "json" };
|
||||
import a49 from "./app-definitions/ticket-tailor.json" with { type: "json" };
|
||||
import a50 from "./app-definitions/asana.json" with { type: "json" };
|
||||
import a51 from "./app-definitions/box.json" with { type: "json" };
|
||||
import a52 from "./app-definitions/mem0.json" with { type: "json" };
|
||||
import a53 from "./app-definitions/pagerduty.json" with { type: "json" };
|
||||
import a54 from "./app-definitions/similarweb.json" with { type: "json" };
|
||||
import a55 from "./app-definitions/xero.json" with { type: "json" };
|
||||
import a56 from "./app-definitions/gmail.json" with { type: "json" };
|
||||
import a57 from "./app-definitions/google-drive.json" with { type: "json" };
|
||||
import a58 from "./app-definitions/google-docs.json" with { type: "json" };
|
||||
import a59 from "./app-definitions/google-sheets.json" with { type: "json" };
|
||||
import a60 from "./app-definitions/google-slides.json" with { type: "json" };
|
||||
import a61 from "./app-definitions/google-calendar.json" with { type: "json" };
|
||||
import a62 from "./app-definitions/google-chat.json" with { type: "json" };
|
||||
import a63 from "./app-definitions/google-people.json" with { type: "json" };
|
||||
import a64 from "./app-definitions/google-workspace-search.json" with { type: "json" };
|
||||
import a0 from "./app-definitions/agentmail.json" with { type: "json" };
|
||||
import a1 from "./app-definitions/zapier.json" with { type: "json" };
|
||||
import a2 from "./app-definitions/github.json" with { type: "json" };
|
||||
import a3 from "./app-definitions/slack.json" with { type: "json" };
|
||||
import a4 from "./app-definitions/microsoft-teams.json" with { type: "json" };
|
||||
import a5 from "./app-definitions/telegram.json" with { type: "json" };
|
||||
import a6 from "./app-definitions/discord.json" with { type: "json" };
|
||||
import a7 from "./app-definitions/notion.json" with { type: "json" };
|
||||
import a8 from "./app-definitions/posthog.json" with { type: "json" };
|
||||
import a9 from "./app-definitions/linear.json" with { type: "json" };
|
||||
import a10 from "./app-definitions/context7.json" with { type: "json" };
|
||||
import a11 from "./app-definitions/shopify.json" with { type: "json" };
|
||||
import a12 from "./app-definitions/composio.json" with { type: "json" };
|
||||
import a13 from "./app-definitions/oauth-generic.json" with { type: "json" };
|
||||
import a14 from "./app-definitions/api-key-generic.json" with { type: "json" };
|
||||
import a15 from "./app-definitions/sentry.json" with { type: "json" };
|
||||
import a16 from "./app-definitions/vercel.json" with { type: "json" };
|
||||
import a17 from "./app-definitions/anthropic.json" with { type: "json" };
|
||||
import a18 from "./app-definitions/jira.json" with { type: "json" };
|
||||
import a19 from "./app-definitions/airtable.json" with { type: "json" };
|
||||
import a20 from "./app-definitions/beehiiv.json" with { type: "json" };
|
||||
import a21 from "./app-definitions/bitly.json" with { type: "json" };
|
||||
import a22 from "./app-definitions/candid.json" with { type: "json" };
|
||||
import a23 from "./app-definitions/cloudflare.json" with { type: "json" };
|
||||
import a24 from "./app-definitions/cloudinary.json" with { type: "json" };
|
||||
import a25 from "./app-definitions/coda.json" with { type: "json" };
|
||||
import a26 from "./app-definitions/hugging-face.json" with { type: "json" };
|
||||
import a27 from "./app-definitions/kernel.json" with { type: "json" };
|
||||
import a28 from "./app-definitions/local-falcon.json" with { type: "json" };
|
||||
import a29 from "./app-definitions/make.json" with { type: "json" };
|
||||
import a30 from "./app-definitions/manufact.json" with { type: "json" };
|
||||
import a31 from "./app-definitions/miro.json" with { type: "json" };
|
||||
import a32 from "./app-definitions/netlify.json" with { type: "json" };
|
||||
import a33 from "./app-definitions/oreilly.json" with { type: "json" };
|
||||
import a34 from "./app-definitions/planetscale.json" with { type: "json" };
|
||||
import a35 from "./app-definitions/resend.json" with { type: "json" };
|
||||
import a36 from "./app-definitions/ticktick.json" with { type: "json" };
|
||||
import a37 from "./app-definitions/todoist.json" with { type: "json" };
|
||||
import a38 from "./app-definitions/webflow.json" with { type: "json" };
|
||||
import a39 from "./app-definitions/wix.json" with { type: "json" };
|
||||
import a40 from "./app-definitions/brex.json" with { type: "json" };
|
||||
import a41 from "./app-definitions/clickhouse.json" with { type: "json" };
|
||||
import a42 from "./app-definitions/egnyte.json" with { type: "json" };
|
||||
import a43 from "./app-definitions/embat.json" with { type: "json" };
|
||||
import a44 from "./app-definitions/mixpanel.json" with { type: "json" };
|
||||
import a45 from "./app-definitions/postman.json" with { type: "json" };
|
||||
import a46 from "./app-definitions/razorpay.json" with { type: "json" };
|
||||
import a47 from "./app-definitions/sanity.json" with { type: "json" };
|
||||
import a48 from "./app-definitions/stripe.json" with { type: "json" };
|
||||
import a49 from "./app-definitions/supabase.json" with { type: "json" };
|
||||
import a50 from "./app-definitions/ticket-tailor.json" with { type: "json" };
|
||||
import a51 from "./app-definitions/asana.json" with { type: "json" };
|
||||
import a52 from "./app-definitions/box.json" with { type: "json" };
|
||||
import a53 from "./app-definitions/mem0.json" with { type: "json" };
|
||||
import a54 from "./app-definitions/pagerduty.json" with { type: "json" };
|
||||
import a55 from "./app-definitions/similarweb.json" with { type: "json" };
|
||||
import a56 from "./app-definitions/xero.json" with { type: "json" };
|
||||
import a57 from "./app-definitions/gmail.json" with { type: "json" };
|
||||
import a58 from "./app-definitions/google-drive.json" with { type: "json" };
|
||||
import a59 from "./app-definitions/google-docs.json" with { type: "json" };
|
||||
import a60 from "./app-definitions/google-sheets.json" with { type: "json" };
|
||||
import a61 from "./app-definitions/google-slides.json" with { type: "json" };
|
||||
import a62 from "./app-definitions/google-calendar.json" with { type: "json" };
|
||||
import a63 from "./app-definitions/google-chat.json" with { type: "json" };
|
||||
import a64 from "./app-definitions/google-people.json" with { type: "json" };
|
||||
import a65 from "./app-definitions/google-workspace-search.json" with { type: "json" };
|
||||
import type { AppDefinition } from "./types/app-definition.js";
|
||||
export const APP_DEFINITIONS=[a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31,a32,a33,a34,a35,a36,a37,a38,a39,a40,a41,a42,a43,a44,a45,a46,a47,a48,a49,a50,a51,a52,a53,a54,a55,a56,a57,a58,a59,a60,a61,a62,a63,a64] as AppDefinition[];
|
||||
export const APP_DEFINITIONS=[a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31,a32,a33,a34,a35,a36,a37,a38,a39,a40,a41,a42,a43,a44,a45,a46,a47,a48,a49,a50,a51,a52,a53,a54,a55,a56,a57,a58,a59,a60,a61,a62,a63,a64,a65] as AppDefinition[];
|
||||
@@ -679,7 +679,7 @@ describe("AppDefinition catalog", () => {
|
||||
"ticktick",
|
||||
"xero",
|
||||
]);
|
||||
expect(APP_STORE_DEFINITIONS).toHaveLength(40);
|
||||
expect(APP_STORE_DEFINITIONS).toHaveLength(41);
|
||||
const connectableSlugs = new Set(
|
||||
CONNECTABLE_APP_DEFINITIONS.map((entry) => entry.slug),
|
||||
);
|
||||
@@ -691,7 +691,7 @@ describe("AppDefinition catalog", () => {
|
||||
expect(storeSlugs.has(slug), slug).toBe(false);
|
||||
}
|
||||
});
|
||||
it("ships complete local branding provenance for all 40 store-visible providers", () => {
|
||||
it("ships complete local branding provenance for all 41 store-visible providers", () => {
|
||||
const uiPublic = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
"../../../ui/public",
|
||||
@@ -711,14 +711,14 @@ describe("AppDefinition catalog", () => {
|
||||
}>;
|
||||
};
|
||||
const visible = manifest.providers.filter((entry) => entry.catalogVisible);
|
||||
expect(visible).toHaveLength(40);
|
||||
expect(visible).toHaveLength(41);
|
||||
expect(new Set(visible.map((entry) => entry.slug))).toHaveProperty(
|
||||
"size",
|
||||
40,
|
||||
41,
|
||||
);
|
||||
expect(new Set(visible.map((entry) => entry.localAsset))).toHaveProperty(
|
||||
"size",
|
||||
40,
|
||||
41,
|
||||
);
|
||||
expect(new Set(APP_STORE_DEFINITIONS.map((entry) => entry.slug))).toEqual(
|
||||
new Set(visible.map((entry) => entry.slug)),
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { AppDefinition, ConnectionMethodDef, FieldDef } from "./types/app-d
|
||||
import type { ToolConnectionOwnership } from "./types/tool-access.js";
|
||||
|
||||
export const CONNECTABLE_APP_SLUGS = new Set([
|
||||
"agentmail",
|
||||
...SELF_SERVE_MCP_CANDIDATES.map((entry) => entry.slug),
|
||||
"zapier",
|
||||
"slack",
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"slug": "agentmail",
|
||||
"name": "AgentMail",
|
||||
"description": "Give agents email inboxes and handle each conversation as a task.",
|
||||
"categories": [
|
||||
"communication"
|
||||
],
|
||||
"featured": false,
|
||||
"branding": {
|
||||
"logoUrl": "/brands/apps/agentmail.svg",
|
||||
"darkLogoUrl": "/brands/apps/agentmail-dark.svg"
|
||||
},
|
||||
"urlPatterns": [
|
||||
"https://console.agentmail.to/*"
|
||||
],
|
||||
"methods": [
|
||||
{
|
||||
"key": "email-agent",
|
||||
"label": "Email with an agent",
|
||||
"purpose": "channel",
|
||||
"provider": "agentmail",
|
||||
"transport": "rest_api",
|
||||
"auth": "api_key",
|
||||
"ownershipModes": [
|
||||
"customer"
|
||||
],
|
||||
"whenToUse": "Assign an inbox to an agent and manage email conversations in tasks.",
|
||||
"credentialFields": [
|
||||
{
|
||||
"key": "apiKey",
|
||||
"label": "AgentMail API key",
|
||||
"type": "password",
|
||||
"placeholder": "am_…",
|
||||
"required": true,
|
||||
"secret": true
|
||||
}
|
||||
],
|
||||
"guidanceMd": "Connect an AgentMail API key, then create or select an inbox for your agent. WebSocket receiving works without a public URL.",
|
||||
"consoleLinks": {
|
||||
"keys": "https://console.agentmail.to",
|
||||
"docs": "https://docs.agentmail.to/inboxes"
|
||||
},
|
||||
"riskTier": "S3",
|
||||
"requiredResourceFilters": [
|
||||
"inbox"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -358,6 +358,7 @@ export const ISSUE_ORIGIN_KINDS = [
|
||||
"routine_execution",
|
||||
"stale_active_run_evaluation",
|
||||
"harness_liveness_escalation",
|
||||
// Historical origin only; automatic productivity reviews have been retired.
|
||||
"issue_productivity_review",
|
||||
"stranded_issue_recovery",
|
||||
"task_watchdog",
|
||||
|
||||
@@ -1122,8 +1122,6 @@ export type {
|
||||
IssueBlockedInboxReason,
|
||||
IssueBlockedInboxSeverity,
|
||||
IssueBlockedInboxState,
|
||||
IssueProductivityReview,
|
||||
IssueProductivityReviewTrigger,
|
||||
IssueRecoveryAction,
|
||||
IssueWatchdog,
|
||||
IssueWatchdogStatus,
|
||||
@@ -2762,3 +2760,6 @@ export type { ExecutionContinuationEnvelope } from "./types/execution-continuati
|
||||
export type { ExecutionProjection, ExecutionReconciliation, ExecutionBlocker } from "./types/execution-projection.js";
|
||||
|
||||
export { EXECUTION_RECONCILIATION_CAUSES, requiresExecutionReconciliation } from "./types/execution-projection.js";
|
||||
|
||||
export * from "./types/email.js";
|
||||
export * from "./validators/email.js";
|
||||
@@ -2,7 +2,7 @@ import type { ConnectionGrantKind, ToolConnectionOwnership, ToolConnectionPurpos
|
||||
export type AppCategory = "ai"|"analytics"|"commerce"|"communication"|"content"|"data"|"developer"|"productivity"|"other";
|
||||
export type OAuthRedirectConstraints = "https-or-loopback-http";
|
||||
export interface FieldDef { key:string; label:string; type:"text"|"password"|"textarea"|"datetime"|"select"|"checkbox"; required?:boolean; advanced?:boolean; hidden?:boolean; placeholder?:string; helperMd?:string; secret?:boolean; prefix?:string; defaultValue?:string|boolean; validation?:{pattern?:string;maxLength?:number}; options?:Array<{value:string;label:string}>; transport?:{location:"query"|"header";name:string;format?:"string"|"csv"|"boolean";omitFalse?:boolean} }
|
||||
export interface ConnectionMethodDef { key:string; label?:string; purpose?:ToolConnectionPurpose; provider?:"slack"|"github"|"discord"|"microsoft-teams"|"telegram"; transport:ToolConnectionTransport; auth:"oauth"|"api_key"|"none"; oauthStrategy?:"paperclip_cloud_connector"|"paperclip_id_connector"; connectorProfile?:string; capabilityProfile?:{key:string;label:string;description?:string}; grantKinds?:ConnectionGrantKind[]; ownershipModes:ToolConnectionOwnership[]; whenToUse:string; defaults?:{serverUrl?:string;serverUrlTemplate?:string;discoveryUrl?:string|null;serviceHost?:string;templateKey?:string;authorizationEndpoint?:string;tokenEndpoint?:string;metadataUrl?:string;scopesHint?:string[];oauthAuthorizationParams?:{access_type?:"offline";prompt?:"consent"};toolArgumentDefaults?:Record<string,unknown>}; tenantFields?:FieldDef[]; extensionFields?:FieldDef[]; configRequirements?:{atLeastOneOf?:string[]}; credentialFields?:FieldDef[]; keyPlacement?:{location:"header"|"query"|"body_json"|"env";name:string;prefix?:string|null}; credentialSources?:{vercelConnect?:{services:string[];principalModes:VercelConnectPrincipalMode[];scopes:string[];header:{name:string;prefix?:string|null}}}; guidanceMd:string; consoleLinks?:{register?:string;keys?:string;settings?:string;docs?:string}; warnings?:string[]; variants?:Array<{key:string;label:string;whenToUse:string;tenantFields?:FieldDef[]}>; riskTier:"S1"|"S2"|"S3"|"S4"; requiredResourceFilters?:string[] }
|
||||
export interface ConnectionMethodDef { key:string; label?:string; purpose?:ToolConnectionPurpose; provider?:"slack"|"github"|"discord"|"microsoft-teams"|"telegram" | "agentmail"; transport:ToolConnectionTransport; auth:"oauth"|"api_key"|"none"; oauthStrategy?:"paperclip_cloud_connector"|"paperclip_id_connector"; connectorProfile?:string; capabilityProfile?:{key:string;label:string;description?:string}; grantKinds?:ConnectionGrantKind[]; ownershipModes:ToolConnectionOwnership[]; whenToUse:string; defaults?:{serverUrl?:string;serverUrlTemplate?:string;discoveryUrl?:string|null;serviceHost?:string;templateKey?:string;authorizationEndpoint?:string;tokenEndpoint?:string;metadataUrl?:string;scopesHint?:string[];oauthAuthorizationParams?:{access_type?:"offline";prompt?:"consent"};toolArgumentDefaults?:Record<string,unknown>}; tenantFields?:FieldDef[]; extensionFields?:FieldDef[]; configRequirements?:{atLeastOneOf?:string[]}; credentialFields?:FieldDef[]; keyPlacement?:{location:"header"|"query"|"body_json"|"env";name:string;prefix?:string|null}; credentialSources?:{vercelConnect?:{services:string[];principalModes:VercelConnectPrincipalMode[];scopes:string[];header:{name:string;prefix?:string|null}}}; guidanceMd:string; consoleLinks?:{register?:string;keys?:string;settings?:string;docs?:string}; warnings?:string[]; variants?:Array<{key:string;label:string;whenToUse:string;tenantFields?:FieldDef[]}>; riskTier:"S1"|"S2"|"S3"|"S4"; requiredResourceFilters?:string[] }
|
||||
export interface AppDefinition { schemaVersion:1; slug:string; name:string; description:string; categories:AppCategory[]; featured?:boolean; branding:{logoUrl:string;darkLogoUrl?:string;backgroundColor?:string;accentColor?:string}; urlPatterns:string[]; docsUrl?:string; setupPrerequisite?:{title:string;description:string;steps?:string[];actionLabel:string;actionUrl:string}; redirectConstraints?:OAuthRedirectConstraints; methods:ConnectionMethodDef[]; suggestable?:boolean; availability?:{available:boolean;reason?:string;robotEmail?:string}; ownershipAvailability?:Partial<Record<ToolConnectionOwnership,boolean>> }
|
||||
|
||||
export type SelfServeMcpAuthMode =
|
||||
|
||||
@@ -11,6 +11,7 @@ export const ATTENTION_SOURCE_KINDS = [
|
||||
"issue_thread_interaction",
|
||||
"join_request",
|
||||
"recovery_action",
|
||||
// Legacy persisted decision sources remain readable; no feed items are generated.
|
||||
"productivity_review",
|
||||
"blocker_attention",
|
||||
"review",
|
||||
|
||||
@@ -5,6 +5,7 @@ export const CHAT_PROVIDERS = [
|
||||
"discord",
|
||||
"microsoft-teams",
|
||||
"telegram",
|
||||
"agentmail",
|
||||
] as const;
|
||||
export type ChatProvider = (typeof CHAT_PROVIDERS)[number];
|
||||
|
||||
@@ -202,10 +203,16 @@ export interface ChatEndpointSetupSecret {
|
||||
webhookSecret: string;
|
||||
}
|
||||
|
||||
export type ChannelPublicationMode = "automatic" | "explicit";
|
||||
export type ExternalMessageExecutionPolicy = "restricted" | "agent";
|
||||
|
||||
export interface ChatEndpoint {
|
||||
id: string;
|
||||
companyId: string;
|
||||
connectionId: string;
|
||||
/** Older clients omit these fields; defaults are automatic/restricted. */
|
||||
publicationMode?: ChannelPublicationMode;
|
||||
externalExecutionPolicy?: ExternalMessageExecutionPolicy;
|
||||
provider: ChatProvider;
|
||||
publicId: string;
|
||||
status: ChatEndpointStatus;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
export interface EmailEnvelope {
|
||||
from: string;
|
||||
to: string[];
|
||||
cc?: string[];
|
||||
bcc?: string[];
|
||||
replyTo?: string[];
|
||||
subject: string;
|
||||
}
|
||||
export type EmailDeliveryOutcome =
|
||||
| "queued"
|
||||
| "sent"
|
||||
| "delivered"
|
||||
| "failed"
|
||||
| "uncertain";
|
||||
export interface EmailMessage extends EmailEnvelope {
|
||||
id: string;
|
||||
providerMessageId: string;
|
||||
direction: "inbound" | "outbound";
|
||||
text: string;
|
||||
fullText: string;
|
||||
commentId: string | null;
|
||||
attachmentIds: string[];
|
||||
timestamp: string;
|
||||
automatic: boolean;
|
||||
}
|
||||
export interface EmailEndpointSummary {
|
||||
id: string;
|
||||
companyId: string;
|
||||
connectionId: string;
|
||||
assignedAgentId: string;
|
||||
address: string | null;
|
||||
status: string;
|
||||
receiveMode: "websocket" | "webhook";
|
||||
lastError: string | null;
|
||||
lastSyncAt: string | null;
|
||||
}
|
||||
export interface EmailPublicationSummary {
|
||||
request?: import("../validators/email.js").EmailSendInput;
|
||||
createdAt?: string;
|
||||
id: string;
|
||||
issueId: string;
|
||||
conversationId: string;
|
||||
outcome: EmailDeliveryOutcome;
|
||||
error: string | null;
|
||||
providerMessageId: string | null;
|
||||
}
|
||||
export interface EmailThreadSummary {
|
||||
conversationId: string;
|
||||
issueId: string;
|
||||
endpoint: EmailEndpointSummary;
|
||||
subject: string;
|
||||
messages: EmailMessage[];
|
||||
publications: EmailPublicationSummary[];
|
||||
}
|
||||
@@ -683,8 +683,6 @@ export type {
|
||||
IssueBlockedInboxReason,
|
||||
IssueBlockedInboxSeverity,
|
||||
IssueBlockedInboxState,
|
||||
IssueProductivityReview,
|
||||
IssueProductivityReviewTrigger,
|
||||
IssueRecoveryAction,
|
||||
SuccessfulRunHandoffState,
|
||||
SuccessfulRunHandoffStateKind,
|
||||
@@ -1066,3 +1064,5 @@ export type {
|
||||
} from "./plugin.js";
|
||||
export * from "./app-definition.js";
|
||||
export * from "./chat-channels.js";
|
||||
|
||||
export * from "./email.js";
|
||||
@@ -537,22 +537,6 @@ export interface IssueUnblockDescriptor {
|
||||
action: string;
|
||||
}
|
||||
|
||||
export type IssueProductivityReviewTrigger =
|
||||
| "no_comment_streak"
|
||||
| "long_active_duration"
|
||||
| "high_churn";
|
||||
|
||||
export interface IssueProductivityReview {
|
||||
reviewIssueId: string;
|
||||
reviewIdentifier: string | null;
|
||||
status: IssueStatus;
|
||||
priority: IssuePriority;
|
||||
trigger: IssueProductivityReviewTrigger | null;
|
||||
noCommentStreak: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface IssueRecoveryAction {
|
||||
id: string;
|
||||
companyId: string;
|
||||
@@ -846,7 +830,6 @@ export interface Issue {
|
||||
unblockDescriptor?: IssueUnblockDescriptor | null;
|
||||
blockedTransitionAt?: Date | null;
|
||||
blockedOwnerNotifiedAt?: Date | null;
|
||||
productivityReview?: IssueProductivityReview | null;
|
||||
activeRecoveryAction?: IssueRecoveryAction | null;
|
||||
successfulRunHandoff?: SuccessfulRunHandoffState | null;
|
||||
executionBlocker?: ExecutionBlocker | null;
|
||||
@@ -919,7 +902,6 @@ export type CompactIssue = Pick<
|
||||
blockerAttention?: IssueBlockerAttention;
|
||||
reviewAttention?: IssueReviewAttention;
|
||||
blockedInboxAttention?: IssueBlockedInboxAttention | null;
|
||||
productivityReview?: IssueProductivityReview | null;
|
||||
scheduledRetry?: IssueScheduledRetry | null;
|
||||
liveDescendantCount?: number;
|
||||
myLastTouchAt?: Date | null;
|
||||
|
||||
@@ -242,6 +242,8 @@ export const resetAgentSessionSchema = z.object({
|
||||
export type ResetAgentSession = z.infer<typeof resetAgentSessionSchema>;
|
||||
|
||||
export const testAdapterEnvironmentSchema = z.object({
|
||||
/** Saved agent whose redacted environment entries are restored for this probe. */
|
||||
agentId: z.string().guid().optional(),
|
||||
/** One-shot provider keys for a probe. Never persist these in agent config. */
|
||||
testCredentials: z.object({
|
||||
ANTHROPIC_API_KEY: z.string().max(16384),
|
||||
|
||||
@@ -5,6 +5,6 @@ const appBrandAssetUrlSchema=z.string().refine((value)=>{
|
||||
try{return new URL(value).protocol==="https:";}catch{return false;}
|
||||
},{message:"Brand assets must be HTTPS URLs or local /brands/apps SVG/PNG paths"});
|
||||
const field=z.object({key:z.string().min(1),label:z.string().min(1),type:z.enum(["text","password","textarea","datetime","select","checkbox"]),required:z.boolean().optional(),advanced:z.boolean().optional(),hidden:z.boolean().optional(),placeholder:z.string().optional(),helperMd:z.string().optional(),secret:z.boolean().optional(),prefix:z.string().optional(),defaultValue:z.union([z.string(),z.boolean()]).optional(),validation:z.object({pattern:z.string().optional(),maxLength:z.number().int().positive().optional()}).optional(),options:z.array(z.object({value:z.string(),label:z.string()})).optional(),transport:z.object({location:z.enum(["query","header"]),name:z.string().min(1),format:z.enum(["string","csv","boolean"]).optional(),omitFalse:z.boolean().optional()}).optional()}).superRefine((v,c)=>{if(v.required&&v.type!=="checkbox"&&!v.placeholder)c.addIssue({code:"custom",message:"Required fields need placeholders",path:["placeholder"]});if(v.type==="select"&&(!v.options||v.options.length===0))c.addIssue({code:"custom",message:"Select fields need options",path:["options"]});if(v.hidden&&v.defaultValue===undefined)c.addIssue({code:"custom",message:"Hidden fields need defaults",path:["defaultValue"]})});
|
||||
export const connectionMethodDefSchema=z.object({key:z.string().min(1),label:z.string().min(1).optional(),purpose:toolConnectionPurposeSchema.optional(),provider:z.enum(["slack","github","discord","microsoft-teams","telegram"]).optional(),transport:toolConnectionTransportSchema,auth:z.enum(["oauth","api_key","none"]),oauthStrategy:z.enum(["paperclip_cloud_connector","paperclip_id_connector"]).optional(),connectorProfile:z.string().regex(/^[a-z0-9]+(?:[.-][a-z0-9]+)*$/).optional(),capabilityProfile:z.object({key:z.string().min(1),label:z.string().min(1),description:z.string().min(1).optional()}).optional(),grantKinds:z.array(connectionGrantKindSchema).min(1).optional(),ownershipModes:z.array(toolConnectionOwnershipSchema).min(1),whenToUse:z.string().min(1),defaults:z.object({serverUrl:z.string().url().optional(),serverUrlTemplate:z.string().regex(/^https:\/\//).optional(),discoveryUrl:z.string().url().nullable().optional(),serviceHost:z.string().optional(),templateKey:z.string().optional(),authorizationEndpoint:z.string().url().optional(),tokenEndpoint:z.string().url().optional(),metadataUrl:z.string().url().optional(),scopesHint:z.array(z.string()).optional(),oauthAuthorizationParams:z.object({access_type:z.literal("offline").optional(),prompt:z.literal("consent").optional()}).optional(),toolArgumentDefaults:z.record(z.string(),z.unknown()).optional()}).optional(),tenantFields:z.array(field).optional(),extensionFields:z.array(field).optional(),configRequirements:z.object({atLeastOneOf:z.array(z.string().min(1)).min(1).optional()}).optional(),credentialFields:z.array(field).optional(),keyPlacement:z.object({location:z.enum(["header","query","body_json","env"]),name:z.string().min(1),prefix:z.string().nullable().optional()}).optional(),credentialSources:z.object({vercelConnect:z.object({services:z.array(z.string().min(1)).min(1),principalModes:z.array(z.enum(["app","user"])).min(1),scopes:z.array(z.string().min(1)).min(1),header:z.object({name:z.string().min(1),prefix:z.string().nullable().optional()})}).optional()}).optional(),guidanceMd:z.string().min(1),consoleLinks:z.object({register:z.string().url().optional(),keys:z.string().url().optional(),settings:z.string().url().optional(),docs:z.string().url().optional()}).optional(),warnings:z.array(z.string()).optional(),variants:z.array(z.object({key:z.string(),label:z.string(),whenToUse:z.string(),tenantFields:z.array(field).optional()})).optional(),riskTier:z.enum(["S1","S2","S3","S4"]),requiredResourceFilters:z.array(z.string()).optional()}).superRefine((v,c)=>{const purpose=v.purpose??"tool";if(v.transport==="chat_sdk"&&purpose!=="channel")c.addIssue({code:"custom",message:"Chat SDK methods must be channel connections",path:["purpose"]});if(purpose==="channel"&&v.transport!=="chat_sdk")c.addIssue({code:"custom",message:"Channel connections must use the Chat SDK transport",path:["transport"]});if(purpose==="channel"&&!v.provider)c.addIssue({code:"custom",message:"Channel connections require a chat provider",path:["provider"]});if(v.auth==="api_key"&&!v.keyPlacement&&purpose!=="channel")c.addIssue({code:"custom",message:"API-key tool methods require keyPlacement",path:["keyPlacement"]});if(v.oauthStrategy&&v.auth!=="oauth")c.addIssue({code:"custom",message:"OAuth strategies require OAuth auth",path:["oauthStrategy"]});if(v.oauthStrategy&&!v.connectorProfile)c.addIssue({code:"custom",message:"Paperclip Cloud connector methods require connectorProfile",path:["connectorProfile"]});if(v.connectorProfile&&!v.oauthStrategy)c.addIssue({code:"custom",message:"connectorProfile requires a Paperclip Cloud OAuth strategy",path:["connectorProfile"]});if(v.credentialSources?.vercelConnect&&(v.transport!=="mcp_remote"||v.auth==="none"))c.addIssue({code:"custom",message:"Vercel Connect requires an authenticated remote MCP method",path:["credentialSources","vercelConnect"]});const keys=new Set([...(v.tenantFields??[]),...(v.extensionFields??[])].map((entry)=>entry.key));for(const key of v.configRequirements?.atLeastOneOf??[])if(!keys.has(key))c.addIssue({code:"custom",message:"Config requirement references an unknown field",path:["configRequirements","atLeastOneOf"]});if(v.defaults?.serverUrl&&v.defaults.serverUrlTemplate)c.addIssue({code:"custom",message:"Use either serverUrl or serverUrlTemplate",path:["defaults"]});for(const placeholder of v.defaults?.serverUrlTemplate?.matchAll(/\{([a-zA-Z0-9_-]+)\}/g)??[])if(!keys.has(placeholder[1]))c.addIssue({code:"custom",message:"Server URL template references an unknown field",path:["defaults","serverUrlTemplate"]})});
|
||||
export const connectionMethodDefSchema=z.object({key:z.string().min(1),label:z.string().min(1).optional(),purpose:toolConnectionPurposeSchema.optional(),provider:z.enum(["slack","github","discord","microsoft-teams","telegram","agentmail"]).optional(),transport:toolConnectionTransportSchema,auth:z.enum(["oauth","api_key","none"]),oauthStrategy:z.enum(["paperclip_cloud_connector","paperclip_id_connector"]).optional(),connectorProfile:z.string().regex(/^[a-z0-9]+(?:[.-][a-z0-9]+)*$/).optional(),capabilityProfile:z.object({key:z.string().min(1),label:z.string().min(1),description:z.string().min(1).optional()}).optional(),grantKinds:z.array(connectionGrantKindSchema).min(1).optional(),ownershipModes:z.array(toolConnectionOwnershipSchema).min(1),whenToUse:z.string().min(1),defaults:z.object({serverUrl:z.string().url().optional(),serverUrlTemplate:z.string().regex(/^https:\/\//).optional(),discoveryUrl:z.string().url().nullable().optional(),serviceHost:z.string().optional(),templateKey:z.string().optional(),authorizationEndpoint:z.string().url().optional(),tokenEndpoint:z.string().url().optional(),metadataUrl:z.string().url().optional(),scopesHint:z.array(z.string()).optional(),oauthAuthorizationParams:z.object({access_type:z.literal("offline").optional(),prompt:z.literal("consent").optional()}).optional(),toolArgumentDefaults:z.record(z.string(),z.unknown()).optional()}).optional(),tenantFields:z.array(field).optional(),extensionFields:z.array(field).optional(),configRequirements:z.object({atLeastOneOf:z.array(z.string().min(1)).min(1).optional()}).optional(),credentialFields:z.array(field).optional(),keyPlacement:z.object({location:z.enum(["header","query","body_json","env"]),name:z.string().min(1),prefix:z.string().nullable().optional()}).optional(),credentialSources:z.object({vercelConnect:z.object({services:z.array(z.string().min(1)).min(1),principalModes:z.array(z.enum(["app","user"])).min(1),scopes:z.array(z.string().min(1)).min(1),header:z.object({name:z.string().min(1),prefix:z.string().nullable().optional()})}).optional()}).optional(),guidanceMd:z.string().min(1),consoleLinks:z.object({register:z.string().url().optional(),keys:z.string().url().optional(),settings:z.string().url().optional(),docs:z.string().url().optional()}).optional(),warnings:z.array(z.string()).optional(),variants:z.array(z.object({key:z.string(),label:z.string(),whenToUse:z.string(),tenantFields:z.array(field).optional()})).optional(),riskTier:z.enum(["S1","S2","S3","S4"]),requiredResourceFilters:z.array(z.string()).optional()}).superRefine((v,c)=>{const purpose=v.purpose??"tool";if(v.transport==="chat_sdk"&&purpose!=="channel")c.addIssue({code:"custom",message:"Chat SDK methods must be channel connections",path:["purpose"]});if(purpose==="channel"&&v.transport!=="chat_sdk"&&!(v.provider==="agentmail"&&v.transport==="rest_api"))c.addIssue({code:"custom",message:"Channel connections must use the Chat SDK transport",path:["transport"]});if(purpose==="channel"&&!v.provider)c.addIssue({code:"custom",message:"Channel connections require a chat provider",path:["provider"]});if(v.auth==="api_key"&&!v.keyPlacement&&purpose!=="channel")c.addIssue({code:"custom",message:"API-key tool methods require keyPlacement",path:["keyPlacement"]});if(v.oauthStrategy&&v.auth!=="oauth")c.addIssue({code:"custom",message:"OAuth strategies require OAuth auth",path:["oauthStrategy"]});if(v.oauthStrategy&&!v.connectorProfile)c.addIssue({code:"custom",message:"Paperclip Cloud connector methods require connectorProfile",path:["connectorProfile"]});if(v.connectorProfile&&!v.oauthStrategy)c.addIssue({code:"custom",message:"connectorProfile requires a Paperclip Cloud OAuth strategy",path:["connectorProfile"]});if(v.credentialSources?.vercelConnect&&(v.transport!=="mcp_remote"||v.auth==="none"))c.addIssue({code:"custom",message:"Vercel Connect requires an authenticated remote MCP method",path:["credentialSources","vercelConnect"]});const keys=new Set([...(v.tenantFields??[]),...(v.extensionFields??[])].map((entry)=>entry.key));for(const key of v.configRequirements?.atLeastOneOf??[])if(!keys.has(key))c.addIssue({code:"custom",message:"Config requirement references an unknown field",path:["configRequirements","atLeastOneOf"]});if(v.defaults?.serverUrl&&v.defaults.serverUrlTemplate)c.addIssue({code:"custom",message:"Use either serverUrl or serverUrlTemplate",path:["defaults"]});for(const placeholder of v.defaults?.serverUrlTemplate?.matchAll(/\{([a-zA-Z0-9_-]+)\}/g)??[])if(!keys.has(placeholder[1]))c.addIssue({code:"custom",message:"Server URL template references an unknown field",path:["defaults","serverUrlTemplate"]})});
|
||||
export const appDefinitionSchema=z.object({schemaVersion:z.literal(1),slug:z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),name:z.string().min(1),description:z.string().min(1),categories:z.array(z.enum(["ai","analytics","commerce","communication","content","data","developer","productivity","other"])).min(1),featured:z.boolean().optional(),branding:z.object({logoUrl:appBrandAssetUrlSchema,darkLogoUrl:appBrandAssetUrlSchema.optional(),backgroundColor:z.string().optional(),accentColor:z.string().optional()}),urlPatterns:z.array(z.string()),docsUrl:z.string().url().optional(),setupPrerequisite:z.object({title:z.string().min(1),description:z.string().min(1),steps:z.array(z.string().min(1)).min(1).optional(),actionLabel:z.string().min(1),actionUrl:z.string().url()} ).optional(),redirectConstraints:z.enum(["https-or-loopback-http"]).optional(),methods:z.array(connectionMethodDefSchema).min(1),suggestable:z.boolean().optional(),availability:z.object({available:z.boolean(),reason:z.string().optional(),robotEmail:z.string().optional()}).optional(),ownershipAvailability:z.object({platform_shared:z.boolean().optional(),platform_provisioned:z.boolean().optional(),customer:z.boolean().optional(),dcr:z.boolean().optional()}).optional()});
|
||||
export const appDefinitionsSchema=z.array(appDefinitionSchema).superRefine((v,c)=>{const s=new Set<string>();v.forEach((a,i)=>{if(s.has(a.slug))c.addIssue({code:"custom",message:"Duplicate slug",path:[i,"slug"]});s.add(a.slug)})});
|
||||
@@ -69,7 +69,7 @@ const chatEndpointCredentialsSchema = z
|
||||
|
||||
export const createChatEndpointSchema = z
|
||||
.object({
|
||||
provider: chatProviderSchema,
|
||||
provider: chatProviderSchema.exclude(["agentmail"]),
|
||||
assignedAgentId: z.string().uuid(),
|
||||
applicationId: z.string().uuid().optional(),
|
||||
name: z.string().trim().min(1).max(160).optional(),
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const address = z.string().trim().email().max(320);
|
||||
const addresses = z.array(address).max(50);
|
||||
export const emailEndpointSetupSchema = z
|
||||
.object({
|
||||
assignedAgentId: z.string().uuid(),
|
||||
applicationId: z.string().uuid().optional(),
|
||||
apiKey: z.string().min(1).max(4096).optional(),
|
||||
credentialConnectionId: z.string().uuid().optional(),
|
||||
inboxId: address.optional(),
|
||||
username: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9._-]+$/)
|
||||
.max(64)
|
||||
.optional(),
|
||||
domain: z.string().max(253).optional(),
|
||||
receiveMode: z.enum(["websocket", "webhook"]).default("websocket"),
|
||||
idempotencyKey: z.string().uuid(),
|
||||
})
|
||||
.strict()
|
||||
.refine((v) => Boolean(v.apiKey) !== Boolean(v.credentialConnectionId), {
|
||||
message: "Supply an API key or a saved connection, not both",
|
||||
});
|
||||
|
||||
export const emailSendSchema = z
|
||||
.object({
|
||||
endpointId: z.string().uuid(),
|
||||
parentIssueId: z.string().uuid().optional(),
|
||||
conversationId: z.string().uuid().optional(),
|
||||
replyToMessageId: z.string().min(1).max(998).optional(),
|
||||
replyAll: z.boolean().default(false),
|
||||
to: addresses.optional(),
|
||||
cc: addresses.optional(),
|
||||
bcc: addresses.optional(),
|
||||
subject: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(998)
|
||||
.regex(/^[^\r\n]+$/)
|
||||
.optional(),
|
||||
text: z.string().trim().min(1).max(100_000),
|
||||
attachmentIds: z.array(z.string().uuid()).max(20).default([]),
|
||||
idempotencyKey: z.string().uuid(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((v, ctx) => {
|
||||
const fail = (message: string) => ctx.addIssue({ code: "custom", message });
|
||||
if (v.conversationId) {
|
||||
if (!v.replyToMessageId) fail("A reply requires its exact message ID");
|
||||
if (v.parentIssueId || v.to || v.cc || v.bcc || v.subject)
|
||||
fail(
|
||||
"Reply recipients come from the original message; use replyAll explicitly",
|
||||
);
|
||||
} else {
|
||||
if (!v.parentIssueId || !v.to?.length || !v.subject)
|
||||
fail("A new email requires a parent task, recipient, and subject");
|
||||
if (v.replyToMessageId || v.replyAll)
|
||||
fail("A new email cannot be a reply");
|
||||
}
|
||||
});
|
||||
export type EmailEndpointSetupInput = z.infer<typeof emailEndpointSetupSchema>;
|
||||
export type EmailSendInput = z.infer<typeof emailSendSchema>;
|
||||
|
||||
export const emailConnectionSchema = z
|
||||
.object({
|
||||
apiKey: z.string().min(1).max(4096),
|
||||
grantKind: z.enum(["user", "organization"]).default("user"),
|
||||
allAgents: z.boolean().default(false),
|
||||
agentIds: z.array(z.string().uuid()).max(500).default([]),
|
||||
idempotencyKey: z.string().uuid(),
|
||||
})
|
||||
.strict();
|
||||
export type EmailConnectionInput = z.infer<typeof emailConnectionSchema>;
|
||||
@@ -977,3 +977,5 @@ export * from "./skill-policy.js";
|
||||
export * from "./provider-trace.js";
|
||||
export * from "./app-definition.js";
|
||||
export * from "./chat-channels.js";
|
||||
|
||||
export * from "./email.js";
|
||||
Reference in new issue
Block a user