diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml index e99dfc12f0..07b49bd055 100644 --- a/.speakeasy/out.openapi.yaml +++ b/.speakeasy/out.openapi.yaml @@ -11595,6 +11595,1409 @@ paths: x-speakeasy-name-override: update x-speakeasy-react-hook: name: UpdateMcpServer + /rpc/nlpolicies.clearSessionVerdict: + post: + description: Clear an active session verdict, releasing the session from quarantine. + operationId: clearNLPolicySessionVerdict + parameters: + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ClearSessionVerdictRequestBody' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/NLPolicySessionVerdict' + description: OK response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: clearSessionVerdict nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: clearSessionVerdict + x-speakeasy-react-hook: + name: NLPoliciesClearSessionVerdict + type: mutation + /rpc/nlpolicies.create: + post: + description: Create a new natural-language policy. + operationId: createNLPolicy + parameters: + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreatePolicyRequestBody' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/NLPolicy' + description: OK response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: createPolicy nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: create + x-speakeasy-react-hook: + name: NLPoliciesCreate + type: mutation + /rpc/nlpolicies.delete: + post: + description: Delete a natural-language policy. + operationId: deleteNLPolicy + parameters: + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DeletePolicyRequestBody' + required: true + responses: + "204": + description: No Content response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: deletePolicy nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: delete + x-speakeasy-react-hook: + name: NLPoliciesDelete + type: mutation + /rpc/nlpolicies.get: + get: + description: Get a natural-language policy by ID. + operationId: getNLPolicy + parameters: + - allowEmptyValue: true + description: The policy ID. + in: query + name: policy_id + required: true + schema: + description: The policy ID. + format: uuid + type: string + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/NLPolicy' + description: OK response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: getPolicy nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: get + x-speakeasy-react-hook: + name: NLPoliciesGet + type: query + /rpc/nlpolicies.getReplayRun: + get: + description: Get a replay run by ID. + operationId: getNLPolicyReplayRun + parameters: + - allowEmptyValue: true + description: The replay run ID. + in: query + name: run_id + required: true + schema: + description: The replay run ID. + format: uuid + type: string + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/NLPolicyReplayRun' + description: OK response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: getReplayRun nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: getReplayRun + x-speakeasy-react-hook: + name: NLPoliciesGetReplayRun + type: query + /rpc/nlpolicies.list: + get: + description: List all NL policies for the current project (or org-wide). + operationId: listNLPolicies + parameters: + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ListPoliciesResponseBody' + description: OK response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: listPolicies nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: list + x-speakeasy-react-hook: + name: NLPoliciesList + type: query + /rpc/nlpolicies.listDecisions: + get: + description: List recorded decisions produced by a natural-language policy. + operationId: listNLPolicyDecisions + parameters: + - allowEmptyValue: true + description: The policy ID. + in: query + name: policy_id + required: true + schema: + description: The policy ID. + format: uuid + type: string + - allowEmptyValue: true + description: Filter by decision (ALLOW | BLOCK | JUDGE_ERROR). + in: query + name: decision + schema: + description: Filter by decision (ALLOW | BLOCK | JUDGE_ERROR). + enum: + - ALLOW + - BLOCK + - JUDGE_ERROR + type: string + - allowEmptyValue: true + description: Filter by whether the decision was enforced. + in: query + name: enforced + schema: + description: Filter by whether the decision was enforced. + type: boolean + - allowEmptyValue: true + description: Filter by decider (static_rule | llm_judge | fail_mode | session_quarantine). + in: query + name: decided_by + schema: + description: Filter by decider (static_rule | llm_judge | fail_mode | session_quarantine). + enum: + - static_rule + - llm_judge + - fail_mode + - session_quarantine + type: string + - allowEmptyValue: true + description: Only include decisions at or after this RFC3339 timestamp. + in: query + name: since + schema: + description: Only include decisions at or after this RFC3339 timestamp. + format: date-time + type: string + - allowEmptyValue: true + description: Filter by source MCP session ID. + in: query + name: session_id + schema: + description: Filter by source MCP session ID. + type: string + - allowEmptyValue: true + description: Cursor to fetch the next page of results. + in: query + name: cursor + schema: + description: Cursor to fetch the next page of results. + type: string + - allowEmptyValue: true + description: Maximum number of results to return per page. + in: query + name: limit + schema: + description: Maximum number of results to return per page. + format: int64 + maximum: 200 + minimum: 1 + type: integer + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ListDecisionsResponseBody' + description: OK response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: listDecisions nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: listDecisions + x-speakeasy-react-hook: + name: NLPoliciesListDecisions + type: query + /rpc/nlpolicies.listReplayResults: + get: + description: List per-sample results for a replay run. + operationId: listNLPolicyReplayResults + parameters: + - allowEmptyValue: true + description: The replay run ID. + in: query + name: run_id + required: true + schema: + description: The replay run ID. + format: uuid + type: string + - allowEmptyValue: true + description: Filter by decision (ALLOW | BLOCK | JUDGE_ERROR). + in: query + name: decision + schema: + description: Filter by decision (ALLOW | BLOCK | JUDGE_ERROR). + enum: + - ALLOW + - BLOCK + - JUDGE_ERROR + type: string + - allowEmptyValue: true + description: Cursor to fetch the next page of results. + in: query + name: cursor + schema: + description: Cursor to fetch the next page of results. + type: string + - allowEmptyValue: true + description: Maximum number of results to return per page. + in: query + name: limit + schema: + description: Maximum number of results to return per page. + format: int64 + maximum: 200 + minimum: 1 + type: integer + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ListReplayResultsResponseBody' + description: OK response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: listReplayResults nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: listReplayResults + x-speakeasy-react-hook: + name: NLPoliciesListReplayResults + type: query + /rpc/nlpolicies.listSessionVerdicts: + get: + description: List session verdicts for a natural-language policy. + operationId: listNLPolicySessionVerdicts + parameters: + - allowEmptyValue: true + description: The policy ID. + in: query + name: policy_id + required: true + schema: + description: The policy ID. + format: uuid + type: string + - allowEmptyValue: true + description: If true, only return currently quarantined sessions. + in: query + name: active_only + schema: + description: If true, only return currently quarantined sessions. + type: boolean + - allowEmptyValue: true + description: Cursor to fetch the next page of results. + in: query + name: cursor + schema: + description: Cursor to fetch the next page of results. + type: string + - allowEmptyValue: true + description: Maximum number of results to return per page. + in: query + name: limit + schema: + description: Maximum number of results to return per page. + format: int64 + maximum: 200 + minimum: 1 + type: integer + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ListSessionVerdictsResponseBody' + description: OK response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: listSessionVerdicts nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: listSessionVerdicts + x-speakeasy-react-hook: + name: NLPoliciesListSessionVerdicts + type: query + /rpc/nlpolicies.replay: + post: + description: Start a replay run for a natural-language policy over historical chat samples. + operationId: replayNLPolicy + parameters: + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ReplayRequestBody' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/NLPolicyReplayRun' + description: OK response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: replay nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: replay + x-speakeasy-react-hook: + name: NLPoliciesReplay + type: mutation + /rpc/nlpolicies.setMode: + post: + description: Set the mode of a natural-language policy (audit | enforce | disabled). + operationId: setNLPolicyMode + parameters: + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SetModeRequestBody' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/NLPolicy' + description: OK response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: setMode nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: setMode + x-speakeasy-react-hook: + name: NLPoliciesSetMode + type: mutation + /rpc/nlpolicies.update: + post: + description: Update a natural-language policy. + operationId: updateNLPolicy + parameters: + - allowEmptyValue: true + description: API Key header + in: header + name: Gram-Key + schema: + description: API Key header + type: string + - allowEmptyValue: true + description: Session header + in: header + name: Gram-Session + schema: + description: Session header + type: string + - allowEmptyValue: true + description: project header + in: header + name: Gram-Project + schema: + description: project header + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UpdatePolicyRequestBody' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/NLPolicy' + description: OK response. + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'bad_request: request is invalid' + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unauthorized: unauthorized access' + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'forbidden: permission denied' + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'not_found: resource not found' + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'conflict: resource already exists' + "415": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unsupported_media: unsupported media type' + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'invalid: request contains one or more invalidation fields' + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'unexpected: an unexpected error occurred' + "502": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: 'gateway_error: an unexpected error occurred' + security: + - apikey_header_Gram-Key: [] + project_slug_header_Gram-Project: [] + - project_slug_header_Gram-Project: [] + session_header_Gram-Session: [] + - {} + summary: updatePolicy nlpolicies + tags: + - nlpolicies + x-speakeasy-group: nlpolicies + x-speakeasy-name-override: update + x-speakeasy-react-hook: + name: NLPoliciesUpdate + type: mutation /rpc/organizations.createPortalSession: post: description: Create a webhook portal session. @@ -27867,6 +29270,15 @@ components: type: string description: Warning message shown to the user in the terminal description: Unified result for all Claude Code hook events with proper response structure + ClearSessionVerdictRequestBody: + type: object + properties: + verdict_id: + type: string + description: The verdict ID. + format: uuid + required: + - verdict_id CloneClientFromOAuthProxyProviderForm: type: object properties: @@ -28294,6 +29706,30 @@ components: description: Optional URL-safe identifier. Auto-generated from name if omitted. required: - name + CreatePolicyRequestBody: + type: object + properties: + description: + type: string + fail_mode: + type: string + description: fail_open | fail_closed (default fail_open) + name: + type: string + nl_prompt: + type: string + static_rules: + type: string + description: JSON-encoded rules array (default "[]") + targets: + type: array + items: + type: string + description: Evaluation targets. + required: + - name + - nl_prompt + - targets CreatePortalSessionResult: type: object properties: @@ -28586,6 +30022,9 @@ components: name: type: string description: The policy name. If omitted, a name will be auto-generated. + nl_prompt: + type: string + description: LLM judge prompt for natural-language evaluation. presidio_entities: type: array items: @@ -28601,6 +30040,11 @@ components: items: type: string description: Detection sources to enable. + targets: + type: array + items: + type: string + description: Evaluation targets. user_message: type: string description: Optional message shown to end users when this policy blocks an action or surfaces a flagged finding. @@ -29036,6 +30480,15 @@ components: description: The ID of the variation that was deleted required: - variation_id + DeletePolicyRequestBody: + type: object + properties: + policy_id: + type: string + description: The policy ID. + format: uuid + required: + - policy_id DeleteRequestBody: type: object properties: @@ -31278,6 +32731,18 @@ components: required: - chats - total + ListDecisionsResponseBody: + type: object + properties: + decisions: + type: array + items: + $ref: '#/components/schemas/NLPolicyDecision' + next_cursor: + type: string + description: Cursor for the next page of results. + required: + - decisions ListDeploymentForm: type: object properties: @@ -31499,6 +32964,15 @@ components: description: The plugins in the organization. required: - plugins + ListPoliciesResponseBody: + type: object + properties: + policies: + type: array + items: + $ref: '#/components/schemas/NLPolicy' + required: + - policies ListProjectsPayload: type: object properties: @@ -31580,6 +33054,18 @@ components: description: Result type for listing remote_sessions. required: - items + ListReplayResultsResponseBody: + type: object + properties: + next_cursor: + type: string + description: Cursor for the next page of results. + results: + type: array + items: + $ref: '#/components/schemas/NLPolicyReplayResult' + required: + - results ListResourcesResult: type: object properties: @@ -31729,6 +33215,18 @@ components: description: Result type for listing remote MCP servers required: - remote_mcp_servers + ListSessionVerdictsResponseBody: + type: object + properties: + next_cursor: + type: string + description: Cursor for the next page of results. + verdicts: + type: array + items: + $ref: '#/components/schemas/NLPolicySessionVerdict' + required: + - verdicts ListShadowMCPApprovalsResult: type: object properties: @@ -32270,6 +33768,279 @@ components: required: - name - count + NLPolicy: + type: object + properties: + created_at: + type: string + description: RFC3339 timestamp. + format: date-time + description: + type: string + description: Author-facing summary. + fail_mode: + type: string + description: fail_open | fail_closed — judge error/timeout behavior in enforce mode. + enum: + - fail_open + - fail_closed + id: + type: string + description: The NL policy ID. + format: uuid + mode: + type: string + description: audit | enforce | disabled. + enum: + - audit + - enforce + - disabled + name: + type: string + description: Policy name. + nl_prompt: + type: string + description: The natural-language judge prompt. + project_id: + type: string + description: The project ID. Empty when org-wide. + format: uuid + static_rules: + type: string + description: JSON-encoded static rule list (see spec §6 grammar). + targets: + type: array + items: + type: string + description: 'Evaluation targets (CheckScope values: user_messages | llm_responses | tool_arguments | tool_responses).' + updated_at: + type: string + description: RFC3339 timestamp. + format: date-time + version: + type: integer + description: Incremented on each update. + format: int64 + required: + - id + - name + - nl_prompt + - targets + - mode + - fail_mode + - static_rules + - version + - created_at + - updated_at + NLPolicyDecision: + type: object + properties: + chat_id: + type: string + description: Source chat (optional). + format: uuid + created_at: + type: string + description: RFC3339 timestamp. + format: date-time + decided_by: + type: string + description: static_rule | llm_judge | fail_mode | session_quarantine. + enum: + - static_rule + - llm_judge + - fail_mode + - session_quarantine + decision: + type: string + description: ALLOW | BLOCK | JUDGE_ERROR. + enum: + - ALLOW + - BLOCK + - JUDGE_ERROR + enforced: + type: boolean + description: True when mode=enforce AND decision=BLOCK. + id: + type: string + description: Decision row ID. + format: uuid + judge_latency_ms: + type: integer + description: Round-trip latency of the LLM call (when applicable). + format: int64 + mode: + type: string + description: Snapshot of policy mode at decision time. + enum: + - audit + - enforce + - disabled + nl_policy_id: + type: string + description: Policy that produced this decision. + format: uuid + nl_policy_version: + type: integer + description: Policy version snapshot at decision time. + format: int64 + reason: + type: string + description: Short human-readable reason. + session_id: + type: string + description: Source MCP session ID. + tool_urn: + type: string + description: Tool that was being called. + required: + - id + - nl_policy_id + - nl_policy_version + - tool_urn + - decision + - decided_by + - mode + - enforced + - created_at + NLPolicyReplayResult: + type: object + properties: + chat_message_id: + type: string + description: Source chat message replayed. + format: uuid + created_at: + type: string + description: RFC3339. + format: date-time + decision: + type: string + description: ALLOW | BLOCK | JUDGE_ERROR. + enum: + - ALLOW + - BLOCK + - JUDGE_ERROR + id: + type: string + description: Result row ID. + format: uuid + judge_latency_ms: + type: integer + format: int64 + reason: + type: string + description: Judge reason. + replay_run_id: + type: string + description: Parent run. + format: uuid + tool_urn: + type: string + description: Tool that was called originally. + required: + - id + - replay_run_id + - decision + - created_at + NLPolicyReplayRun: + type: object + properties: + completed_at: + type: string + description: RFC3339 — null until completed. + format: date-time + counts: + type: string + description: 'JSON-encoded counts: {would_block, would_allow, judge_error}.' + id: + type: string + description: Run ID. + format: uuid + nl_policy_id: + type: string + description: Policy under test. + format: uuid + nl_policy_version: + type: integer + description: Policy version snapshot. + format: int64 + sample_filter: + type: string + description: JSON-encoded filter envelope. + started_at: + type: string + description: RFC3339. + format: date-time + status: + type: string + description: pending | running | completed | failed. + enum: + - pending + - running + - completed + - failed + required: + - id + - nl_policy_id + - nl_policy_version + - status + - sample_filter + - started_at + NLPolicySessionVerdict: + type: object + properties: + chat_id: + type: string + description: Source chat. + format: uuid + cleared_at: + type: string + description: RFC3339 — non-null when cleared. + format: date-time + cleared_by: + type: string + description: Clearing user ID. + format: uuid + created_at: + type: string + description: RFC3339. + format: date-time + id: + type: string + description: Verdict row ID. + format: uuid + nl_policy_id: + type: string + description: Policy that produced the verdict. + format: uuid + nl_policy_version: + type: integer + description: Policy version snapshot. + format: int64 + quarantined_at: + type: string + description: RFC3339 — null when verdict=OK. + format: date-time + reason: + type: string + description: Why. + session_id: + type: string + description: Quarantined session. + verdict: + type: string + description: OK | QUARANTINED. + enum: + - OK + - QUARANTINED + required: + - id + - session_id + - nl_policy_id + - nl_policy_version + - verdict + - created_at NotModified: type: object properties: @@ -34127,6 +35898,19 @@ components: description: The rendered prompt required: - prompt + ReplayRequestBody: + type: object + properties: + policy_id: + type: string + description: The policy ID. + format: uuid + sample_filter: + type: string + description: JSON-encoded sample filter envelope. + required: + - policy_id + - sample_filter ResolveChallengeForm: type: object properties: @@ -34379,6 +36163,9 @@ components: name: type: string description: The policy name. + nl_prompt: + type: string + description: LLM judge prompt for natural-language evaluation. Present when nl_policy category is active. pending_messages: type: integer description: Number of messages not yet analyzed at the current policy version. @@ -34402,6 +36189,11 @@ components: items: type: string description: Detection sources enabled for this policy. + targets: + type: array + items: + type: string + description: Evaluation targets. When empty, all scopes are evaluated. total_messages: type: integer description: Total number of messages in the project. @@ -35346,6 +37138,23 @@ components: maxLength: 40 required: - toolset_slug + SetModeRequestBody: + type: object + properties: + mode: + type: string + description: Target mode. + enum: + - audit + - enforce + - disabled + policy_id: + type: string + description: The policy ID. + format: uuid + required: + - policy_id + - mode SetOrganizationWhitelistRequestBody: type: object properties: @@ -36847,6 +38656,32 @@ components: - id - plugin_id - display_name + UpdatePolicyRequestBody: + type: object + properties: + description: + type: string + fail_mode: + type: string + description: fail_open | fail_closed + name: + type: string + nl_prompt: + type: string + policy_id: + type: string + description: The policy ID. + format: uuid + static_rules: + type: string + description: JSON-encoded rules array + targets: + type: array + items: + type: string + description: Evaluation targets. + required: + - policy_id UpdatePromptTemplateForm: type: object properties: @@ -37027,6 +38862,9 @@ components: name: type: string description: The policy name. + nl_prompt: + type: string + description: LLM judge prompt for natural-language evaluation. presidio_entities: type: array items: @@ -37042,6 +38880,11 @@ components: items: type: string description: Detection sources to enable. + targets: + type: array + items: + type: string + description: Evaluation targets. user_message: type: string description: Optional message shown to end users when this policy blocks an action or surfaces a flagged finding. Send an empty string to clear. @@ -37934,6 +39777,8 @@ tags: description: Manages metadata for the MCP install page shown to users. - name: mcpServers description: Managing MCP servers, which configure authentication, environment, and backend selection for an MCP server. + - name: nlpolicies + description: Manage natural-language session policies and view their decisions, quarantines, and replay runs. - name: organizations description: Organization membership, invitations, and directory. - name: otelForwarding diff --git a/client/dashboard/src/components/page-header.tsx b/client/dashboard/src/components/page-header.tsx index b60e3540b7..d2101e0a26 100644 --- a/client/dashboard/src/components/page-header.tsx +++ b/client/dashboard/src/components/page-header.tsx @@ -71,7 +71,6 @@ const breadcrumbSubstitutions = { "audit-logs": "Audit Logs", "admin-settings": "Admin Settings", "risk-overview": "Risk Overview", - "risk-events": "Risk Events", "risk-policies": "Risk Policies", // The URL segments `slack` and `clis` are preserved for backwards // compatibility, but the sidebar/route titles were rebranded — map them diff --git a/client/dashboard/src/pages/security/NLPolicyAuditFeedTab.tsx b/client/dashboard/src/pages/security/NLPolicyAuditFeedTab.tsx new file mode 100644 index 0000000000..682e9ff638 --- /dev/null +++ b/client/dashboard/src/pages/security/NLPolicyAuditFeedTab.tsx @@ -0,0 +1,172 @@ +import { Badge } from "@/components/ui/badge"; +import { Card } from "@/components/ui/card"; +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, +} from "@/components/ui/sheet"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { Type } from "@/components/ui/type"; +import { useNlPoliciesListDecisions } from "@gram/client/react-query/index.js"; +import type { NLPolicy } from "@gram/client/models/components/nlpolicy.js"; +import type { NLPolicyDecision } from "@gram/client/models/components/nlpolicydecision.js"; +import { useParams } from "react-router"; +import { useState } from "react"; + +const decisionVariant = ( + d: NLPolicyDecision["decision"], +): "default" | "destructive" | "secondary" => { + if (d === "BLOCK") return "destructive"; + if (d === "JUDGE_ERROR") return "secondary"; + return "default"; +}; + +export default function NLPolicyAuditFeedTab({ policy }: { policy: NLPolicy }) { + const { orgSlug, projectSlug } = useParams(); + const { data, isLoading } = useNlPoliciesListDecisions({ + policyId: policy.id, + }); + const decisions = data?.decisions ?? []; + const [selected, setSelected] = useState(null); + + if (isLoading) { + return ( + + + Loading decisions… + + + ); + } + + if (decisions.length === 0) { + return ( + + + No decisions recorded yet for this policy. + + + ); + } + + return ( + + + Last {decisions.length} decisions, newest first. + + + + + Time + Decision + Tool + Mode + Decided by + Reason + + + + {decisions.map((d) => ( + setSelected(d)} + className="cursor-pointer" + > + + {d.createdAt.toLocaleTimeString()} + + + + {d.decision} + + + {d.toolUrn} + {d.mode} + {d.decidedBy} + + {d.reason ?? "—"} + + + ))} + +
+ !o && setSelected(null)}> + + {selected && ( + <> + + Decision detail + + {selected.createdAt.toLocaleString()} + + +
+
+ + {selected.decision} + + {selected.mode} + by {selected.decidedBy} + {selected.enforced && ( + Enforced + )} +
+
+ + Tool URN + +
+ {selected.toolUrn} +
+
+ {selected.reason && ( +
+ + Reason + +
+ {selected.reason} +
+
+ )} +
+
+ + Policy version + +
v{selected.nlPolicyVersion}
+
+ {selected.judgeLatencyMs != null && ( +
+ + Judge latency + +
{selected.judgeLatencyMs}ms
+
+ )} +
+ {selected.sessionId && orgSlug && projectSlug && ( + + Open session → + + )} +
+ + )} +
+
+
+ ); +} diff --git a/client/dashboard/src/pages/security/NLPolicyConfigureTab.tsx b/client/dashboard/src/pages/security/NLPolicyConfigureTab.tsx new file mode 100644 index 0000000000..1d23cd1c61 --- /dev/null +++ b/client/dashboard/src/pages/security/NLPolicyConfigureTab.tsx @@ -0,0 +1,247 @@ +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import { TextArea } from "@/components/ui/textarea"; +import { Type } from "@/components/ui/type"; +import { + invalidateAllNlPoliciesGet, + invalidateAllNlPoliciesList, + useNlPoliciesSetModeMutation, + useNlPoliciesUpdateMutation, +} from "@gram/client/react-query/index.js"; +import type { NLPolicy } from "@gram/client/models/components/nlpolicy.js"; +import { useQueryClient } from "@tanstack/react-query"; +import { Loader2 } from "lucide-react"; +import { useState } from "react"; + +import NLPolicyModePromoteModal from "./NLPolicyModePromoteModal"; +import NLPolicyReplayModal from "./NLPolicyReplayModal"; +import { CHECK_SCOPE_META, type CheckScope } from "./policy-data"; + +const TEMPLATES: { name: string; body: string }[] = [ + { + name: "No deletes against prod", + body: 'Refuse any tool call whose name or description indicates a destructive operation (delete, drop, truncate, purge) when the target MCP slug is tagged "production". Allow read operations.', + }, + { + name: "No PII egress", + body: "Refuse any tool call that sends customer PII (email, SSN, phone, credit card) to an external destination such as Slack, email, or webhook.", + }, + { + name: "MCP allowlist", + body: "Refuse any call to an external-MCP that is not on the configured allowlist.", + }, + { + name: "No secrets in args", + body: "Refuse any tool call whose arguments contain values that look like API keys, passwords, or other credentials.", + }, +]; + +type FailMode = NLPolicy["failMode"]; +type Mode = NLPolicy["mode"]; +const ALL_CHECK_SCOPES = Object.keys(CHECK_SCOPE_META) as CheckScope[]; + +export default function NLPolicyConfigureTab({ policy }: { policy: NLPolicy }) { + const queryClient = useQueryClient(); + const [name, setName] = useState(policy.name); + const [description, setDescription] = useState(policy.description ?? ""); + const [nlPrompt, setNlPrompt] = useState(policy.nlPrompt); + const [targets, setTargets] = useState( + policy.targets as CheckScope[], + ); + const [failMode, setFailMode] = useState(policy.failMode); + const [replayOpen, setReplayOpen] = useState(false); + const [promoteOpen, setPromoteOpen] = useState(false); + + const invalidate = () => { + invalidateAllNlPoliciesGet(queryClient); + invalidateAllNlPoliciesList(queryClient); + }; + + const updateMutation = useNlPoliciesUpdateMutation({ + onSuccess: invalidate, + }); + const setModeMutation = useNlPoliciesSetModeMutation({ + onSuccess: invalidate, + }); + + const onSave = () => { + updateMutation.mutate({ + request: { + updatePolicyRequestBody: { + policyId: policy.id, + name, + description, + nlPrompt, + targets, + failMode, + }, + }, + }); + }; + + const onPickTemplate = (idx: number) => { + const template = TEMPLATES[idx]; + if (template) setNlPrompt(template.body); + }; + + const onPromoteConfirm = (mode: Mode) => { + setModeMutation.mutate({ + request: { + setModeRequestBody: { + policyId: policy.id, + mode, + }, + }, + }); + }; + + const isSaving = updateMutation.isPending; + + return ( + +
+ + setName(v)} /> +
+ +
+ + setDescription(v)} /> +
+ +
+ +