1080 lines · 48.9 KB · TypeScript
RawDownload
// ---------------------------------------------------------------------------// core-tools plugin//// Built-in plugin that contributes agent-facing static tools for configuring// executor-level primitives over the v2 surface. Agent-facing connection setup// should hand users to the web UI for pasted credentials; low-level creation// through this plugin only accepts provider refs.// --------------------------------------------------------------------------- import { Effect, Schema } from "effect"; import type { Connection, ConnectionInputOrigin, CreateConnectionInput } from "./connection";import {  AuthTemplateSlug,  ConnectionName,  IntegrationSlug,  NO_AUTH_TEMPLATE,  OAuthClientSlug,  OAuthState,  ProviderItemId,  ProviderKey,  type Owner,} from "./ids";import { definePlugin, tool, type StaticToolSchema } from "./plugin";import { HealthCheckResult, isToolSyncHealth } from "./health-check";import { ToolPolicyActionSchema } from "./policies";import type { Tool } from "./tool";import { ToolResult } from "./tool-result"; const schemaToStandard = <A, I>(schema: Schema.Decoder<A, I>): StaticToolSchema<A, I> =>  Schema.toStandardSchemaV1(Schema.toStandardJSONSchemaV1(schema) as never) as StaticToolSchema<    A,    I  >; const OwnerSchema = Schema.Literals(["org", "user"]);const OAuthGrantSchema = Schema.Literals(["authorization_code", "client_credentials"]); // ---------------------------------------------------------------------------// Schemas// --------------------------------------------------------------------------- const IntegrationOutput = Schema.Struct({  slug: Schema.String,  description: Schema.String,  kind: Schema.String,  canRemove: Schema.Boolean,  canRefresh: Schema.Boolean,}); const IntegrationsListOutput = Schema.Struct({  integrations: Schema.Array(IntegrationOutput),}); const IntegrationRemoveInput = Schema.Struct({ slug: Schema.String }); const DetectInput = Schema.Struct({ url: Schema.String });const DetectOutput = Schema.Struct({  results: Schema.Array(    Schema.Struct({      kind: Schema.String,      confidence: Schema.Literals(["high", "medium", "low"]),      endpoint: Schema.String,      name: Schema.String,      slug: Schema.String,    }),  ),}); const ConnectionOutput = Schema.Struct({  owner: OwnerSchema,  name: Schema.String,  integration: Schema.String,  template: Schema.String,  provider: Schema.String,  address: Schema.String,  identityLabel: Schema.optional(Schema.NullOr(Schema.String)),  description: Schema.optional(Schema.NullOr(Schema.String)),  expiresAt: Schema.NullOr(Schema.Number),  oauthClient: Schema.NullOr(Schema.String),  oauthClientOwner: Schema.NullOr(OwnerSchema),  oauthScope: Schema.NullOr(Schema.String),  lastHealth: Schema.NullOr(HealthCheckResult),}); const ConnectionsListInput = Schema.Struct({  integration: Schema.optional(Schema.String),  owner: Schema.optional(OwnerSchema),  verbose: Schema.optional(Schema.Boolean),}); /** Lean per-connection shape for list scans. The default projection summarizes *  the full `oauthScope` grant string as `oauthScopeCount` and trims health *  probe diagnostics. Those optional fields are populated only for `verbose: *  true`. */const ConnectionListItem = Schema.Struct({  owner: OwnerSchema,  name: Schema.String,  integration: Schema.String,  template: Schema.String,  provider: Schema.String,  address: Schema.String,  identityLabel: Schema.optional(Schema.NullOr(Schema.String)),  description: Schema.optional(Schema.NullOr(Schema.String)),  expiresAt: Schema.NullOr(Schema.Number),  oauthClient: Schema.NullOr(Schema.String),  oauthClientOwner: Schema.NullOr(OwnerSchema),  oauthScopeCount: Schema.NullOr(Schema.Number),  oauthScope: Schema.optional(Schema.NullOr(Schema.String)),  lastHealth: Schema.NullOr(HealthCheckResult),});const ConnectionsListOutput = Schema.Struct({  connections: Schema.Array(ConnectionListItem),}); const ConnectionCreateHandoffInput = Schema.Struct({  integration: Schema.String,  owner: Schema.optional(OwnerSchema),  template: Schema.optional(Schema.String),  label: Schema.optional(Schema.String),});const ConnectionCreateHandoffOutput = Schema.Struct({  url: Schema.String,  instructions: Schema.String,}); const ConnectionFromInput = Schema.Struct({  provider: Schema.String,  id: Schema.String,});const ConnectionInputOriginInput = Schema.Struct({ from: ConnectionFromInput });const ConnectionCreateInput = Schema.Struct({  owner: OwnerSchema,  name: Schema.String,  integration: Schema.String,  template: Schema.String,  identityLabel: Schema.optional(Schema.NullOr(Schema.String)),  from: Schema.optional(ConnectionFromInput),  inputs: Schema.optional(Schema.Record(Schema.String, ConnectionInputOriginInput)),}).check(  Schema.makeFilter((payload) => {    const originCount =      (payload.from === undefined ? 0 : 1) + (payload.inputs === undefined ? 0 : 1);    // The no-auth template ("none") binds zero credentials — both `from` and    // `inputs` are legitimately absent (public MCP servers, public REST APIs).    // Mirror the engine, which accepts an empty input set only for this    // template; a stray origin would wire a credential the connection can't    // hold, so reject any. Every other template needs exactly one origin.    const isNoAuth = String(payload.template) === String(NO_AUTH_TEMPLATE);    if (isNoAuth) {      if (originCount > 0) {        return 'A no-auth connection (template "none") takes no provider credential origin';      }    } else if (originCount !== 1) {      return "Expected exactly one provider credential origin";    }    if (payload.inputs !== undefined && Object.keys(payload.inputs).length === 0) {      return "Expected at least one provider credential input";    }    return undefined;  }),);const ConnectionRefInput = Schema.Struct({  owner: OwnerSchema,  name: Schema.String,  integration: Schema.String,}); const ToolOutput = Schema.Struct({  address: Schema.String,  owner: OwnerSchema,  integration: Schema.String,  connection: Schema.String,  name: Schema.String,  pluginId: Schema.String,  description: Schema.String,});const ConnectionsRefreshOutput = Schema.Struct({  tools: Schema.Array(ToolOutput),  lastHealth: Schema.NullOr(HealthCheckResult),}); const RemovedOutput = Schema.Struct({ removed: Schema.Boolean });const CancelledOutput = Schema.Struct({ cancelled: Schema.Boolean }); const ProvidersOutput = Schema.Struct({  providers: Schema.Array(Schema.String),}); const ProviderItemsInput = Schema.Struct({ provider: Schema.String });const ProviderItemsOutput = Schema.Struct({  items: Schema.Array(Schema.Struct({ id: Schema.String, name: Schema.String })),}); const PolicyOutput = Schema.Struct({  id: Schema.String,  owner: OwnerSchema,  pattern: Schema.String,  action: Schema.String,  position: Schema.String,});const PoliciesListOutput = Schema.Struct({  policies: Schema.Array(PolicyOutput),}); const PolicyCreateInput = Schema.Struct({  owner: OwnerSchema,  pattern: Schema.String,  action: ToolPolicyActionSchema,});const PolicyUpdateInput = Schema.Struct({  id: Schema.String,  owner: OwnerSchema,  pattern: Schema.optional(Schema.String),  action: Schema.optional(ToolPolicyActionSchema),});const PolicyRemoveInput = Schema.Struct({  id: Schema.String,  owner: OwnerSchema,}); const OAuthClientOutput = Schema.Struct({  owner: OwnerSchema,  slug: Schema.String,  grant: OAuthGrantSchema,  authorizationUrl: Schema.String,  tokenUrl: Schema.String,  resource: Schema.optional(Schema.NullOr(Schema.String)),  clientId: Schema.String,  origin: Schema.Union([    Schema.Struct({ kind: Schema.Literal("manual") }),    Schema.Struct({      kind: Schema.Literal("dynamic_client_registration"),      integration: Schema.optional(Schema.NullOr(Schema.String)),    }),  ]),});const OAuthClientsListOutput = Schema.Struct({  clients: Schema.Array(OAuthClientOutput),});// No `clientSecret`: a confidential client's secret must never cross the agent// boundary (it would land in the LLM context window). This tool registers a// PUBLIC client only; a secret-bearing app is registered by the human through// `oauth.clients.createHandoff`, which deep-links them to the web form.const OAuthCreateClientInput = Schema.Struct({  owner: OwnerSchema,  slug: Schema.String,  authorizationUrl: Schema.String,  tokenUrl: Schema.String,  grant: OAuthGrantSchema,  clientId: Schema.String,  resource: Schema.optional(Schema.NullOr(Schema.String)),  /** Integration whose connect dialog registered this manual app. Recorded so   *  the picker can match it by intent (exact) instead of by root domain. */  originIntegration: Schema.optional(Schema.NullOr(Schema.String)),});// Browser-handoff for a CONFIDENTIAL OAuth app: carries only the NON-secret// fields the form pre-fills. The client secret is typed by the human in the web// UI, exactly like a pasted connection credential, so it never reaches the// agent. Mirrors `ConnectionCreateHandoffInput`.const OAuthCreateClientHandoffInput = Schema.Struct({  integration: Schema.String,  owner: Schema.optional(OwnerSchema),  slug: Schema.optional(Schema.String),  grant: Schema.optional(OAuthGrantSchema),  clientId: Schema.optional(Schema.String),  authorizationUrl: Schema.optional(Schema.String),  tokenUrl: Schema.optional(Schema.String),  resource: Schema.optional(Schema.NullOr(Schema.String)),  label: Schema.optional(Schema.String),});const OAuthCreateClientHandoffOutput = Schema.Struct({  url: Schema.String,  instructions: Schema.String,});const OAuthClientOutputRef = Schema.Struct({  client: Schema.String,});const OAuthRegisterDynamicInput = Schema.Struct({  owner: OwnerSchema,  slug: Schema.String,  issuer: Schema.optional(Schema.NullOr(Schema.String)),  registrationEndpoint: Schema.String,  authorizationUrl: Schema.String,  tokenUrl: Schema.String,  resource: Schema.optional(Schema.NullOr(Schema.String)),  scopes: Schema.Array(Schema.String),  tokenEndpointAuthMethodsSupported: Schema.optional(Schema.Array(Schema.String)),  clientName: Schema.optional(Schema.String),  redirectUri: Schema.optional(Schema.NullOr(Schema.String)),  originIntegration: Schema.optional(Schema.NullOr(Schema.String)),});const OAuthRemoveClientInput = Schema.Struct({  owner: OwnerSchema,  slug: Schema.String,});const OAuthProbeInput = Schema.Struct({  url: Schema.String,});const OAuthProbeOutput = Schema.Struct({  issuer: Schema.optional(Schema.NullOr(Schema.String)),  authorizationUrl: Schema.String,  tokenUrl: Schema.String,  resource: Schema.optional(Schema.NullOr(Schema.String)),  scopesSupported: Schema.optional(Schema.Array(Schema.String)),  registrationEndpoint: Schema.optional(Schema.NullOr(Schema.String)),  tokenEndpointAuthMethodsSupported: Schema.optional(Schema.Array(Schema.String)),  clientIdMetadataDocumentSupported: Schema.optional(Schema.Boolean),});const OAuthStartInput = Schema.Struct({  client: Schema.String,  clientOwner: OwnerSchema,  owner: OwnerSchema,  name: Schema.String,  integration: Schema.String,  template: Schema.String,  identityLabel: Schema.optional(Schema.NullOr(Schema.String)),  redirectUri: Schema.optional(Schema.NullOr(Schema.String)),});const OAuthStartOutput = Schema.Union([  Schema.Struct({    status: Schema.Literal("connected"),    connection: ConnectionOutput,  }),  Schema.Struct({    status: Schema.Literal("redirect"),    authorizationUrl: Schema.String,    state: Schema.String,  }),]);const OAuthCancelInput = Schema.Struct({  state: Schema.String,}); // Standard-schema versions for the tool() builder.const IntegrationsListOutputStd = schemaToStandard(IntegrationsListOutput);const IntegrationRemoveInputStd = schemaToStandard(IntegrationRemoveInput);const DetectInputStd = schemaToStandard(DetectInput);const DetectOutputStd = schemaToStandard(DetectOutput);const ConnectionsListInputStd = schemaToStandard(ConnectionsListInput);const ConnectionsListOutputStd = schemaToStandard(ConnectionsListOutput);const ConnectionCreateHandoffInputStd = schemaToStandard(ConnectionCreateHandoffInput);const ConnectionCreateHandoffOutputStd = schemaToStandard(ConnectionCreateHandoffOutput);const ConnectionCreateInputStd = schemaToStandard(ConnectionCreateInput);const ConnectionOutputStd = schemaToStandard(ConnectionOutput);const ConnectionRefInputStd = schemaToStandard(ConnectionRefInput);const ConnectionsRefreshOutputStd = schemaToStandard(ConnectionsRefreshOutput);const RemovedOutputStd = schemaToStandard(RemovedOutput);const CancelledOutputStd = schemaToStandard(CancelledOutput);const ProvidersOutputStd = schemaToStandard(ProvidersOutput);const ProviderItemsInputStd = schemaToStandard(ProviderItemsInput);const ProviderItemsOutputStd = schemaToStandard(ProviderItemsOutput);const PoliciesListOutputStd = schemaToStandard(PoliciesListOutput);const PolicyOutputStd = schemaToStandard(PolicyOutput);const PolicyCreateInputStd = schemaToStandard(PolicyCreateInput);const PolicyUpdateInputStd = schemaToStandard(PolicyUpdateInput);const PolicyRemoveInputStd = schemaToStandard(PolicyRemoveInput);const OAuthClientsListOutputStd = schemaToStandard(OAuthClientsListOutput);const OAuthCreateClientInputStd = schemaToStandard(OAuthCreateClientInput);const OAuthCreateClientHandoffInputStd = schemaToStandard(OAuthCreateClientHandoffInput);const OAuthCreateClientHandoffOutputStd = schemaToStandard(OAuthCreateClientHandoffOutput);const OAuthClientOutputRefStd = schemaToStandard(OAuthClientOutputRef);const OAuthRegisterDynamicInputStd = schemaToStandard(OAuthRegisterDynamicInput);const OAuthRemoveClientInputStd = schemaToStandard(OAuthRemoveClientInput);const OAuthProbeInputStd = schemaToStandard(OAuthProbeInput);const OAuthProbeOutputStd = schemaToStandard(OAuthProbeOutput);const OAuthStartInputStd = schemaToStandard(OAuthStartInput);const OAuthStartOutputStd = schemaToStandard(OAuthStartOutput);const OAuthCancelInputStd = schemaToStandard(OAuthCancelInput); const connectionToOutput = (connection: Connection) => ({  owner: connection.owner,  name: String(connection.name),  integration: String(connection.integration),  template: String(connection.template),  provider: String(connection.provider),  address: String(connection.address),  identityLabel: connection.identityLabel ?? null,  description: connection.description ?? null,  expiresAt: connection.expiresAt ?? null,  oauthClient: connection.oauthClient == null ? null : String(connection.oauthClient),  oauthClientOwner: connection.oauthClientOwner ?? null,  oauthScope: connection.oauthScope ?? null,  lastHealth: connection.lastHealth ?? null,}); /** Number of space-separated grants in an `oauthScope` string, or null when *  the connection carries no scope (static credentials, or an OAuth AS that *  omitted scope). */const oauthScopeCount = (scope: string | null | undefined): number | null =>  scope == null ? null : scope.split(/\s+/).filter(Boolean).length; /** Lean projection for `connections.list`. Summarizes `oauthScope` and health * diagnostics unless `verbose`, where the full grant string is included too. */const connectionToListItem = (connection: Connection, verbose: boolean) => ({  owner: connection.owner,  name: String(connection.name),  integration: String(connection.integration),  template: String(connection.template),  provider: String(connection.provider),  address: String(connection.address),  identityLabel: connection.identityLabel ?? null,  description: connection.description ?? null,  expiresAt: connection.expiresAt ?? null,  oauthClient: connection.oauthClient == null ? null : String(connection.oauthClient),  oauthClientOwner: connection.oauthClientOwner ?? null,  oauthScopeCount: oauthScopeCount(connection.oauthScope),  // Keep full probe diagnostics behind the explicit verbose opt-in.  lastHealth:    connection.lastHealth == null || verbose      ? (connection.lastHealth ?? null)      : {          status: connection.lastHealth.status,          ...(connection.lastHealth.identity !== undefined            ? { identity: connection.lastHealth.identity }            : {}),          checkedAt: connection.lastHealth.checkedAt,        },  ...(verbose ? { oauthScope: connection.oauthScope ?? null } : {}),}); /** How long a non-healthy persisted verdict may be served to an agent before *  it is re-verified. Verdicts are sticky — nothing re-probes them between UI *  visits — so without read-time revalidation an agent keeps reporting *  "unhealthy, reconnect" for a connection that recovered long ago (or was *  never really down: invocation auto-refreshes OAuth tokens, so a stale *  "expired" verdict often describes a working connection). The window is *  short so recovery shows on the next read, but bounds repeated lists from *  hammering a genuinely-down upstream. Healthy verdicts are deliberately *  served as-is: they mislead no one into reconnect guidance, and the UI *  owns their background revalidation. */const NON_HEALTHY_REVALIDATE_MS = 60 * 1000; /** Whether an agent read must re-verify a persisted verdict before reporting *  it. Only probe-refutable non-healthy verdicts qualify: `unknown` and *  missing verdicts carry no reconnect implication, and a tool-sync failure *  verdict cannot be refuted by a credential probe (a successful sync clears *  it instead). */const needsAgentReadRevalidation = (last: HealthCheckResult | null | undefined): boolean =>  (last?.status === "expired" || last?.status === "degraded") && !isToolSyncHealth(last); const toolToOutput = (toolRow: Tool) => ({  address: String(toolRow.address),  owner: toolRow.owner,  integration: String(toolRow.integration),  connection: String(toolRow.connection),  name: String(toolRow.name),  pluginId: toolRow.pluginId,  description: toolRow.description,}); const connectionRefFromInput = (input: typeof ConnectionRefInput.Type) => ({  owner: input.owner as Owner,  integration: IntegrationSlug.make(input.integration),  name: ConnectionName.make(input.name),}); const originFromInput = (  origin: typeof ConnectionInputOriginInput.Type,): ConnectionInputOrigin => ({  from: {    provider: ProviderKey.make(origin.from.provider),    id: ProviderItemId.make(origin.from.id),  },}); const createConnectionInputFromTool = (  input: typeof ConnectionCreateInput.Type,): CreateConnectionInput => {  const base = {    owner: input.owner as Owner,    name: ConnectionName.make(input.name),    integration: IntegrationSlug.make(input.integration),    template: AuthTemplateSlug.make(input.template),    identityLabel: input.identityLabel ?? null,  };   if (input.from !== undefined) {    return {      ...base,      from: {        provider: ProviderKey.make(input.from.provider),        id: ProviderItemId.make(input.from.id),      },    };  }  return {    ...base,    inputs: Object.fromEntries(      Object.entries(input.inputs ?? {}).map(([variable, origin]) => [        variable,        originFromInput(origin),      ]),    ),  };}; const connectionCreateHandoffUrl = (  webBaseUrl: string | undefined,  orgSlug: string | undefined,

Lines 1–500 of 1080.