mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 02:26:12 +02:00
Rebuild on the rebased proposal; sync the generated contract from backend draft 48a4cce
Provenance: paperclipai/telemetry-backend PR #145 commit 48a4ccea6ce89c17f74841fa2022c25f96410c09, artifact dist/client-sdk/paperclip-telemetry.ts, copied verbatim (never hand edited; sha256 0a875a739023f3a776ac9ba4dbed4114096ba5e71753c31bf01e366372d68faf) into packages/shared/src/telemetry/generated/paperclip-telemetry.ts. The stack was rebuilt on proposal commit0f614f9ab(rebased onto masterb41ccf097, where #13758 retired the legacy Composio broker). The three prior adoption commits were cherry-picked unchanged; the rename edits that lived in the former merge commit e9b0ffcb6 (typed wrappers, tests, README, retention map) are restored here. Contract delta versus the previous artifact: `composio_sync` removed from `setup_flow` and `change_source` (no emission site remains), and two enum descriptions widened to name the OAuth access-finalization and Cloud/Vercel callback variants the proposal wires. README Connector Events section: direct Composio MCP connections report `composio`; retained legacy broker records can only be removed and report `composio` (`rest_api` parent) or `custom` (child). Draft — DO NOT MERGE; stacked on proposal/connector-telemetry-events. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
2efc28a3c9
commit
9e5a945efb
4 files changed
+80
-76
No files matched your search
@@ -110,7 +110,8 @@ data paths document their own contract in their own file:
|
||||
|
||||
## Connector Events
|
||||
|
||||
The three `connector.*` events record tool-connector lifecycle and usage for
|
||||
The three connection events (`connection.created`, `connection.updated`,
|
||||
`connection.invoked`) record tool-connector lifecycle and usage for
|
||||
connections whose `connection_purpose` is `tool`. The generated contract
|
||||
remains the authority for their exact dimensions and optionality. These
|
||||
durable rules are not expressible in the generated `string`/`number` types:
|
||||
@@ -119,15 +120,20 @@ durable rules are not expressible in the generated `string`/`number` types:
|
||||
connection's `sourceTemplateKey` only when that key resolves to a reviewed
|
||||
first-party catalog definition; every other connection emits the literal
|
||||
`custom`. `connectorKeyForConnection()` in
|
||||
`server/src/services/connector-telemetry.ts` owns this rule. Composio-synced
|
||||
child connections persist a `toolkitSlug` but no catalog
|
||||
`sourceTemplateKey`, so they report `custom` too; raw toolkit or provider
|
||||
strings are never exported.
|
||||
- `connector.connection_created` and `connector.connection_updated` are
|
||||
`server/src/services/connector-telemetry.ts` owns this rule. Direct
|
||||
Composio MCP connections (catalog slug `composio`, method `mcp`) therefore
|
||||
report `composio`; session URLs, headers, and the tools reached through the
|
||||
aggregator never appear in any dimension. Records left behind by the retired
|
||||
Composio broker (#13758) can only be removed: a legacy parent reports
|
||||
`composio` with `transport: rest_api`, and a legacy child — which has a
|
||||
`toolkitSlug` but no catalog `sourceTemplateKey` — reports `custom`; raw
|
||||
toolkit or provider strings are never exported.
|
||||
- `connection.created` and `connection.updated` are
|
||||
emitted only after the lifecycle write commits, from returned rows. Writes
|
||||
that affect no rows and no-op changes do not emit.
|
||||
- `connector.invocation_completed` is emitted when an invocation reaches a
|
||||
terminal status — best-effort, so duplicate and lost events are possible
|
||||
- `connection.invoked` is emitted when an invocation reaches a
|
||||
terminal status: it records completed invocation attempts and their terminal
|
||||
status, never invocation starts — best-effort, so duplicate and lost events are possible
|
||||
(see the delivery rule below); do not read it as exactly one event per
|
||||
invocation. Its `origin` dimension separates setup tests (the Apps →
|
||||
Test tab) from agent and user calls using the durable test-origin columns.
|
||||
@@ -138,8 +144,8 @@ durable rules are not expressible in the generated `string`/`number` types:
|
||||
bookkeeping itself fails, and a crash between the product write and emission
|
||||
loses that event. Do not treat these events as an exactly-once ledger.
|
||||
|
||||
Use `trackConnectorConnectionCreated()`, `trackConnectorConnectionUpdated()`,
|
||||
and `trackConnectorInvocationCompleted()` from `events.ts` to emit these
|
||||
Use `trackConnectionCreated()`, `trackConnectionUpdated()`,
|
||||
and `trackConnectionInvoked()` from `events.ts` to emit these
|
||||
events.
|
||||
|
||||
## Dimension Values
|
||||
|
||||
@@ -37,18 +37,26 @@ source_ref?: string
|
||||
source_ref_hashed?: boolean
|
||||
}
|
||||
|
||||
export interface PaperclipConnectorConnectionCreatedDimensions {
|
||||
export interface PaperclipConnectionCreatedDimensions {
|
||||
auth_kind: ("oauth" | "api_key" | "none")
|
||||
connector_key: string
|
||||
enabled: boolean
|
||||
setup_flow: ("gallery" | "api" | "example" | "composio_sync")
|
||||
setup_flow: ("gallery" | "api" | "example")
|
||||
status: ("draft" | "active" | "disabled" | "archived")
|
||||
transport: ("mcp_remote" | "rest_api" | "local_stdio")
|
||||
}
|
||||
|
||||
export interface PaperclipConnectorConnectionUpdatedDimensions {
|
||||
export interface PaperclipConnectionInvokedDimensions {
|
||||
connector_key: string
|
||||
duration_seconds?: number
|
||||
origin: ("setup_test" | "agent" | "user" | "system" | "plugin")
|
||||
status: ("succeeded" | "failed" | "denied" | "cancelled" | "timed_out" | "rate_limited")
|
||||
transport: ("mcp_remote" | "rest_api" | "local_stdio")
|
||||
}
|
||||
|
||||
export interface PaperclipConnectionUpdatedDimensions {
|
||||
auth_kind: ("oauth" | "api_key" | "none")
|
||||
change_source: ("update_api" | "gallery_setup" | "oauth_callback" | "credential_refresh" | "archive" | "example" | "composio_sync")
|
||||
change_source: ("api" | "gallery" | "oauth_callback" | "credential_refresh" | "archive" | "example")
|
||||
connector_key: string
|
||||
enabled: boolean
|
||||
previous_enabled: boolean
|
||||
@@ -57,14 +65,6 @@ status: ("draft" | "active" | "disabled" | "archived")
|
||||
transport: ("mcp_remote" | "rest_api" | "local_stdio")
|
||||
}
|
||||
|
||||
export interface PaperclipConnectorInvocationCompletedDimensions {
|
||||
connector_key: string
|
||||
duration_seconds?: number
|
||||
origin: ("setup_test" | "agent" | "user" | "system" | "plugin")
|
||||
status: ("succeeded" | "failed" | "denied" | "cancelled" | "timed_out" | "rate_limited")
|
||||
transport: ("mcp_remote" | "rest_api" | "local_stdio")
|
||||
}
|
||||
|
||||
export interface PaperclipErrorHandlerCrashDimensions {
|
||||
error_code: string
|
||||
}
|
||||
@@ -133,9 +133,9 @@ export type PaperclipEventName =
|
||||
| "agent.task_completed"
|
||||
| "agent.task_run"
|
||||
| "company.imported"
|
||||
| "connector.connection_created"
|
||||
| "connector.connection_updated"
|
||||
| "connector.invocation_completed"
|
||||
| "connection.created"
|
||||
| "connection.invoked"
|
||||
| "connection.updated"
|
||||
| "error.handler_crash"
|
||||
| "goal.created"
|
||||
| "install.completed"
|
||||
@@ -153,9 +153,9 @@ export interface EventDimensionsMap {
|
||||
"agent.task_completed": PaperclipAgentTaskCompletedDimensions;
|
||||
"agent.task_run": PaperclipAgentTaskRunDimensions;
|
||||
"company.imported": PaperclipCompanyImportedDimensions;
|
||||
"connector.connection_created": PaperclipConnectorConnectionCreatedDimensions;
|
||||
"connector.connection_updated": PaperclipConnectorConnectionUpdatedDimensions;
|
||||
"connector.invocation_completed": PaperclipConnectorInvocationCompletedDimensions;
|
||||
"connection.created": PaperclipConnectionCreatedDimensions;
|
||||
"connection.invoked": PaperclipConnectionInvokedDimensions;
|
||||
"connection.updated": PaperclipConnectionUpdatedDimensions;
|
||||
"error.handler_crash": PaperclipErrorHandlerCrashDimensions;
|
||||
"goal.created": PaperclipGoalCreatedDimensions;
|
||||
"install.completed": PaperclipInstallCompletedDimensions;
|
||||
@@ -174,9 +174,9 @@ export const PAPERCLIP_EVENTS = {
|
||||
"agent.task_completed": "agent.task_completed",
|
||||
"agent.task_run": "agent.task_run",
|
||||
"company.imported": "company.imported",
|
||||
"connector.connection_created": "connector.connection_created",
|
||||
"connector.connection_updated": "connector.connection_updated",
|
||||
"connector.invocation_completed": "connector.invocation_completed",
|
||||
"connection.created": "connection.created",
|
||||
"connection.invoked": "connection.invoked",
|
||||
"connection.updated": "connection.updated",
|
||||
"error.handler_crash": "error.handler_crash",
|
||||
"goal.created": "goal.created",
|
||||
"install.completed": "install.completed",
|
||||
@@ -311,7 +311,7 @@ export const PAPERCLIP_ENUM_DESCRIPTIONS = {
|
||||
"unknown": "Source type could not be classified."
|
||||
}
|
||||
},
|
||||
"connector.connection_created": {
|
||||
"connection.created": {
|
||||
"auth_kind": {
|
||||
"oauth": "Connection authenticates with an OAuth flow.",
|
||||
"api_key": "Connection authenticates with a stored API key.",
|
||||
@@ -320,8 +320,7 @@ export const PAPERCLIP_ENUM_DESCRIPTIONS = {
|
||||
"setup_flow": {
|
||||
"gallery": "Connection was created through the app-gallery setup flow.",
|
||||
"api": "Connection was created through the connections API.",
|
||||
"example": "Connection was created or upserted as a bundled example connection.",
|
||||
"composio_sync": "Connection was created by syncing a Composio child connection."
|
||||
"example": "Connection was created or upserted as a bundled example connection."
|
||||
},
|
||||
"status": {
|
||||
"draft": "Connection row exists but setup has not produced a usable configuration yet.",
|
||||
@@ -335,40 +334,7 @@ export const PAPERCLIP_ENUM_DESCRIPTIONS = {
|
||||
"local_stdio": "Connection runs a local MCP server over stdio."
|
||||
}
|
||||
},
|
||||
"connector.connection_updated": {
|
||||
"auth_kind": {
|
||||
"oauth": "Connection authenticates with an OAuth flow.",
|
||||
"api_key": "Connection authenticates with a stored API key.",
|
||||
"none": "Connection requires no authentication."
|
||||
},
|
||||
"change_source": {
|
||||
"update_api": "A connections API update changed the persisted lifecycle state.",
|
||||
"gallery_setup": "An app-gallery setup step changed the persisted lifecycle state.",
|
||||
"oauth_callback": "An OAuth callback completion changed the persisted lifecycle state.",
|
||||
"credential_refresh": "A credential refresh changed the persisted lifecycle state.",
|
||||
"archive": "An archive operation changed the persisted lifecycle state.",
|
||||
"example": "An example-connection upsert changed the persisted lifecycle state.",
|
||||
"composio_sync": "A Composio child-connection sync changed the persisted lifecycle state."
|
||||
},
|
||||
"previous_status": {
|
||||
"draft": "Connection row exists but setup has not produced a usable configuration yet.",
|
||||
"active": "Connection is fully configured and available for use.",
|
||||
"disabled": "Connection is disabled and excluded from tool use.",
|
||||
"archived": "Connection is archived and excluded from tool use."
|
||||
},
|
||||
"status": {
|
||||
"draft": "Connection row exists but setup has not produced a usable configuration yet.",
|
||||
"active": "Connection is fully configured and available for use.",
|
||||
"disabled": "Connection is disabled and excluded from tool use.",
|
||||
"archived": "Connection is archived and excluded from tool use."
|
||||
},
|
||||
"transport": {
|
||||
"mcp_remote": "Connection talks to a remote MCP server over HTTP.",
|
||||
"rest_api": "Connection calls the provider's REST API directly.",
|
||||
"local_stdio": "Connection runs a local MCP server over stdio."
|
||||
}
|
||||
},
|
||||
"connector.invocation_completed": {
|
||||
"connection.invoked": {
|
||||
"origin": {
|
||||
"setup_test": "A human ran the connection's setup test, identified by durable invocation columns: user actor with no run, issue, or gateway reference and a connection id.",
|
||||
"agent": "An agent run invoked the tool.",
|
||||
@@ -390,6 +356,38 @@ export const PAPERCLIP_ENUM_DESCRIPTIONS = {
|
||||
"local_stdio": "Connection runs a local MCP server over stdio."
|
||||
}
|
||||
},
|
||||
"connection.updated": {
|
||||
"auth_kind": {
|
||||
"oauth": "Connection authenticates with an OAuth flow.",
|
||||
"api_key": "Connection authenticates with a stored API key.",
|
||||
"none": "Connection requires no authentication."
|
||||
},
|
||||
"change_source": {
|
||||
"api": "A connections API update changed the persisted lifecycle state.",
|
||||
"gallery": "An app-gallery setup step (finish, OAuth access finalization, or reconnect; Apps gallery and inline task cards) changed the persisted lifecycle state.",
|
||||
"oauth_callback": "An OAuth callback completion (provider OAuth, Paperclip Cloud connector, or Vercel Connect) changed the persisted lifecycle state.",
|
||||
"credential_refresh": "A credential refresh changed the persisted lifecycle state.",
|
||||
"archive": "An archive operation changed the persisted lifecycle state.",
|
||||
"example": "An example-connection upsert changed the persisted lifecycle state."
|
||||
},
|
||||
"previous_status": {
|
||||
"draft": "Connection row exists but setup has not produced a usable configuration yet.",
|
||||
"active": "Connection is fully configured and available for use.",
|
||||
"disabled": "Connection is disabled and excluded from tool use.",
|
||||
"archived": "Connection is archived and excluded from tool use."
|
||||
},
|
||||
"status": {
|
||||
"draft": "Connection row exists but setup has not produced a usable configuration yet.",
|
||||
"active": "Connection is fully configured and available for use.",
|
||||
"disabled": "Connection is disabled and excluded from tool use.",
|
||||
"archived": "Connection is archived and excluded from tool use."
|
||||
},
|
||||
"transport": {
|
||||
"mcp_remote": "Connection talks to a remote MCP server over HTTP.",
|
||||
"rest_api": "Connection calls the provider's REST API directly.",
|
||||
"local_stdio": "Connection runs a local MCP server over stdio."
|
||||
}
|
||||
},
|
||||
"goal.created": {
|
||||
"goal_level": {
|
||||
"company": "Goal applies at company scope.",
|
||||
|
||||
@@ -25,8 +25,8 @@ describe("telemetry retention contract", () => {
|
||||
});
|
||||
|
||||
it("connector telemetry uses enum/count retention", () => {
|
||||
expect(EVENT_RETENTION_CLASS["connector.connection_created"]).toBe("operational_enum_count");
|
||||
expect(EVENT_RETENTION_CLASS["connector.connection_updated"]).toBe("operational_enum_count");
|
||||
expect(EVENT_RETENTION_CLASS["connector.invocation_completed"]).toBe("operational_enum_count");
|
||||
expect(EVENT_RETENTION_CLASS["connection.created"]).toBe("operational_enum_count");
|
||||
expect(EVENT_RETENTION_CLASS["connection.updated"]).toBe("operational_enum_count");
|
||||
expect(EVENT_RETENTION_CLASS["connection.invoked"]).toBe("operational_enum_count");
|
||||
});
|
||||
});
|
||||
@@ -43,8 +43,8 @@ export type RetentionClass = keyof typeof RETENTION_DAYS;
|
||||
* External-system event (Codex CLI) — not yet in PaperclipEventName.
|
||||
* Class: operational_enum_count — 90-day window.
|
||||
*
|
||||
* connector.connection_created / connector.connection_updated /
|
||||
* connector.invocation_completed
|
||||
* connection.created / connection.updated /
|
||||
* connection.invoked
|
||||
* Carry only closed enums, booleans, a coarse rounded-seconds duration, and
|
||||
* the reviewed catalog slug (or the literal "custom") as connector_key. No
|
||||
* token material and no PII.
|
||||
@@ -54,7 +54,7 @@ export const EVENT_RETENTION_CLASS: Partial<Record<string, RetentionClass>> = {
|
||||
"codex.credential_health": "operational_enum_count",
|
||||
"interaction.created": "operational_enum_count",
|
||||
"interaction.resolved": "operational_enum_count",
|
||||
"connector.connection_created": "operational_enum_count",
|
||||
"connector.connection_updated": "operational_enum_count",
|
||||
"connector.invocation_completed": "operational_enum_count",
|
||||
"connection.created": "operational_enum_count",
|
||||
"connection.updated": "operational_enum_count",
|
||||
"connection.invoked": "operational_enum_count",
|
||||
};
|
||||
Reference in new issue
Block a user