@agent-native/core 0.203.1 → 0.204.0-nightly-20261008011018
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/a2a/handlers.js +57 -1
- package/dist/a2a/server.js +37 -1
- package/dist/action.js +22 -1
- package/dist/agent/contain-principal.d.ts +9 -0
- package/dist/agent/contain-principal.js +53 -0
- package/dist/agent/production-agent.js +32 -2
- package/dist/agent/run-manager.js +14 -2
- package/dist/agent/run-store.js +66 -12
- package/dist/agent/thread-message-projection.d.ts +1 -0
- package/dist/agent/thread-message-projection.js +56 -6
- package/dist/audit/actions/export-audit-events.d.ts +1 -1
- package/dist/audit/actions/export-audit-events.js +2 -2
- package/dist/audit/actions/export-audit-ocsf.d.ts +11 -0
- package/dist/audit/actions/export-audit-ocsf.js +183 -0
- package/dist/audit/actions/list-audit-events.d.ts +1 -1
- package/dist/audit/actions/list-audit-events.js +3 -3
- package/dist/audit/config.d.ts +1 -1
- package/dist/audit/config.js +5 -1
- package/dist/audit/index.d.ts +1 -0
- package/dist/audit/index.js +1 -0
- package/dist/audit/ocsf.d.ts +70 -0
- package/dist/audit/ocsf.js +228 -0
- package/dist/audit/record.js +1 -1
- package/dist/audit/store.js +9 -2
- package/dist/audit/types.d.ts +12 -1
- package/dist/cli/connect.js +7 -2
- package/dist/client/chat/agentkit-agent-native.js +104 -24
- package/dist/coding-tools/run-code.js +22 -1
- package/dist/coding-tools/sandbox/local-child-process-adapter.js +20 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +2 -2
- package/dist/file-upload/builder.js +18 -4
- package/dist/framework-tools.js +3 -0
- package/dist/identity/rekey.js +6 -0
- package/dist/localization/core-messages/supplemental/ar-SA.js +15 -0
- package/dist/localization/core-messages/supplemental/de-DE.js +15 -0
- package/dist/localization/core-messages/supplemental/en-US.js +15 -0
- package/dist/localization/core-messages/supplemental/es-ES.js +15 -0
- package/dist/localization/core-messages/supplemental/fr-FR.js +15 -0
- package/dist/localization/core-messages/supplemental/hi-IN.js +15 -0
- package/dist/localization/core-messages/supplemental/ja-JP.js +15 -0
- package/dist/localization/core-messages/supplemental/ko-KR.js +15 -0
- package/dist/localization/core-messages/supplemental/pt-BR.js +15 -0
- package/dist/localization/core-messages/supplemental/zh-CN.js +15 -0
- package/dist/localization/core-messages/supplemental/zh-TW.js +15 -0
- package/dist/localization/mcp-settings-messages.d.ts +15 -0
- package/dist/mcp/actions/create-org-service-token.d.ts +8 -0
- package/dist/mcp/actions/create-org-service-token.js +92 -4
- package/dist/mcp/actions/list-org-service-tokens.d.ts +2 -0
- package/dist/mcp/actions/list-org-service-tokens.js +36 -8
- package/dist/mcp/actions/service-principal-input.d.ts +48 -0
- package/dist/mcp/actions/service-principal-input.js +102 -0
- package/dist/mcp/actions/set-service-principal-lifecycle.d.ts +15 -0
- package/dist/mcp/actions/set-service-principal-lifecycle.js +150 -0
- package/dist/mcp/actions/set-service-principal-policy.d.ts +14 -0
- package/dist/mcp/actions/set-service-principal-policy.js +105 -0
- package/dist/mcp/build-server.js +105 -4
- package/dist/mcp/connect-route.js +116 -4
- package/dist/mcp/connect-store.d.ts +7 -0
- package/dist/mcp/connect-store.js +21 -14
- package/dist/observability/routes.d.ts +4 -4
- package/dist/observability/store.js +11 -5
- package/dist/observability/traces.js +6 -0
- package/dist/observability/types.d.ts +2 -0
- package/dist/org/index.d.ts +2 -2
- package/dist/org/service-principal-guard.d.ts +64 -0
- package/dist/org/service-principal-guard.js +140 -0
- package/dist/org/service-principal-policy.d.ts +104 -0
- package/dist/org/service-principal-policy.js +272 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +2 -2
- package/dist/provider-api/actions/provider-api.d.ts +13 -13
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/action-discovery.js +12 -0
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/core-routes-plugin.js +39 -12
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-schema.js +4 -0
- package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
- package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +59 -70
- package/dist/templates/factory/.agents/skills/review-latest-feedback/references/reproduction-and-verification.md +46 -0
- package/dist/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +33 -0
- package/dist/templates/factory/.agents/skills/review-prs/SKILL.md +5 -3
- package/dist/triggers/actions/manage-automation.d.ts +2 -2
- package/dist/vite/client.js +1 -0
- package/docs/content/audit-log.mdx +15 -0
- package/docs/content/http-api.mdx +21 -2
- package/docs/content/pr-visual-recap.mdx +3 -1
- package/docs/content/template-clips-embed.mdx +1 -1
- package/docs/content/turn-into-app.mdx +118 -0
- package/package.json +4 -4
- package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +59 -70
- package/src/templates/factory/.agents/skills/review-latest-feedback/references/reproduction-and-verification.md +46 -0
- package/src/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +33 -0
- package/src/templates/factory/.agents/skills/review-prs/SKILL.md +5 -3
package/dist/a2a/handlers.js
CHANGED
|
@@ -2,6 +2,8 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import { setResponseHeader, setResponseStatus } from "h3";
|
|
3
3
|
import { AGENT_BACKGROUND_PROCESSOR_A2A, AGENT_BACKGROUND_PROCESSOR_FIELD, dispatchPathTargetsNetlifyBackgroundFunction, isAgentChatDurableBackgroundEnabled, resolveAgentChatProcessRunDispatchPath, } from "../agent/durable-background.js";
|
|
4
4
|
import { trackingIdentityProperties } from "../observability/tracking-identity.js";
|
|
5
|
+
import { parseServiceIdentityEmail } from "../org/service-identity.js";
|
|
6
|
+
import { assertServicePrincipalMayRun, recordServicePrincipalDenial, ServicePrincipalRefusedError, } from "../org/service-principal-guard.js";
|
|
5
7
|
import { findWorkspaceDispatchAgent } from "../server/agent-discovery.js";
|
|
6
8
|
import { withConfiguredAppBasePath } from "../server/app-base-path.js";
|
|
7
9
|
import { getOrigin, isConfiguredAppOrigin } from "../server/google-oauth.js";
|
|
@@ -12,7 +14,7 @@ import { track } from "../tracking/registry.js";
|
|
|
12
14
|
import { hasConfiguredA2ASecret, isA2AProductionRuntime, } from "./auth-policy.js";
|
|
13
15
|
import { callAction } from "./client.js";
|
|
14
16
|
import { sanitizeA2ACorrelationMetadata } from "./correlation.js";
|
|
15
|
-
import { createTask, createOrReuseTask, getTask, getTaskOwnership, updateTask, claimA2ATaskForProcessing, getA2ATaskDispatchState, failStuckA2ATask, failStuckQueuedA2ATask, settleProcessingA2ATask, touchQueuedA2ATaskDispatch, touchProcessingA2ATask, pauseProcessingA2ATask, MAX_A2A_IDEMPOTENCY_KEY_CHARS, A2A_PERSONAL_OWNER_SCOPE, A2A_ORG_ID_OWNER_SCOPE_PREFIX, } from "./task-store.js";
|
|
17
|
+
import { createTask, createOrReuseTask, getTask, getTaskOwnership, updateTask, claimA2ATaskForProcessing, getA2ATaskDispatchState, failStuckA2ATask, failStuckQueuedA2ATask, settleProcessingA2ATask, resetStuckA2ATaskForRetry, touchQueuedA2ATaskDispatch, touchProcessingA2ATask, pauseProcessingA2ATask, MAX_A2A_IDEMPOTENCY_KEY_CHARS, A2A_PERSONAL_OWNER_SCOPE, A2A_ORG_ID_OWNER_SCOPE_PREFIX, } from "./task-store.js";
|
|
16
18
|
const A2A_PROCESS_TASK_PATH = "/_agent-native/a2a/_process-task";
|
|
17
19
|
const PORTABLE_FALLBACK_HANDOFF_TIMEOUT_MS = 1_000;
|
|
18
20
|
const A2A_QUEUED_DISPATCH_STUCK_AFTER_MS = 10_000;
|
|
@@ -246,6 +248,38 @@ export async function processA2ATaskFromQueue(taskId, config, event) {
|
|
|
246
248
|
const verifiedOrgId = typeof processorMeta.verifiedOrgId === "string"
|
|
247
249
|
? processorMeta.verifiedOrgId.trim()
|
|
248
250
|
: undefined;
|
|
251
|
+
let servicePrincipalAllowedActions;
|
|
252
|
+
try {
|
|
253
|
+
const admission = await assertServicePrincipalMayRun(verifiedEmail, verifiedOrgId);
|
|
254
|
+
if (parseServiceIdentityEmail(verifiedEmail)) {
|
|
255
|
+
servicePrincipalAllowedActions = admission.allowedActions;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
if (!(error instanceof ServicePrincipalRefusedError))
|
|
260
|
+
throw error;
|
|
261
|
+
if (error.statusCode === 503) {
|
|
262
|
+
await resetStuckA2ATaskForRetry(taskId, Date.now());
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
if (error.statusCode !== 403)
|
|
266
|
+
throw error;
|
|
267
|
+
await recordServicePrincipalDenial({
|
|
268
|
+
email: verifiedEmail,
|
|
269
|
+
orgId: verifiedOrgId,
|
|
270
|
+
actionName: "a2a:process-task",
|
|
271
|
+
caller: "a2a",
|
|
272
|
+
error,
|
|
273
|
+
});
|
|
274
|
+
await settleProcessingA2ATask(taskId, {
|
|
275
|
+
state: "failed",
|
|
276
|
+
message: {
|
|
277
|
+
role: "agent",
|
|
278
|
+
parts: [{ type: "text", text: error.message }],
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
249
283
|
const requestOrigin = requestOriginFromMetadata(processorMeta) ?? requestOriginFromEvent(event);
|
|
250
284
|
const contextId = processorMeta.contextId ?? undefined;
|
|
251
285
|
const callerMetadata = processorMeta.callerMetadata ?? undefined;
|
|
@@ -261,6 +295,10 @@ export async function processA2ATaskFromQueue(taskId, config, event) {
|
|
|
261
295
|
event.context.__a2aOrgDomain = orgDomainHint;
|
|
262
296
|
if (verifiedOrgId)
|
|
263
297
|
event.context.__a2aVerifiedOrgId = verifiedOrgId;
|
|
298
|
+
if (servicePrincipalAllowedActions !== undefined) {
|
|
299
|
+
event.context.__a2aServicePrincipalAllowedActions =
|
|
300
|
+
servicePrincipalAllowedActions;
|
|
301
|
+
}
|
|
264
302
|
if (verifiedEmail && !resolvedOrgId)
|
|
265
303
|
markExplicitPersonalOrgScope(event);
|
|
266
304
|
}
|
|
@@ -294,6 +332,24 @@ export async function processA2ATaskFromQueue(taskId, config, event) {
|
|
|
294
332
|
}
|
|
295
333
|
}
|
|
296
334
|
const defaultHandler = async (message, context) => {
|
|
335
|
+
const eventContext = context.event?.context;
|
|
336
|
+
const verifiedEmail = typeof eventContext?.__a2aVerifiedEmail === "string"
|
|
337
|
+
? eventContext.__a2aVerifiedEmail
|
|
338
|
+
: undefined;
|
|
339
|
+
const serviceIdentity = parseServiceIdentityEmail(verifiedEmail);
|
|
340
|
+
if (serviceIdentity) {
|
|
341
|
+
const error = new ServicePrincipalRefusedError("service_principal_handoff_unsupported", "The default A2A chat handoff cannot preserve service-principal authorization. Use a service-aware A2A handler.");
|
|
342
|
+
await recordServicePrincipalDenial({
|
|
343
|
+
email: verifiedEmail,
|
|
344
|
+
orgId: typeof eventContext?.__a2aVerifiedOrgId === "string"
|
|
345
|
+
? eventContext.__a2aVerifiedOrgId
|
|
346
|
+
: undefined,
|
|
347
|
+
actionName: "a2a:agent-chat-handoff",
|
|
348
|
+
caller: "a2a",
|
|
349
|
+
error,
|
|
350
|
+
});
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
297
353
|
const text = message.parts
|
|
298
354
|
.filter((p) => p.type === "text")
|
|
299
355
|
.map((p) => p.text)
|
package/dist/a2a/server.js
CHANGED
|
@@ -3,6 +3,8 @@ import * as jose from "jose";
|
|
|
3
3
|
import "../authorization/check-action.js";
|
|
4
4
|
import { redactArgsToJson } from "../audit/redact.js";
|
|
5
5
|
import { extractBearerToken, verifyInternalToken, } from "../integrations/internal-token.js";
|
|
6
|
+
import { parseServiceIdentityEmail } from "../org/service-identity.js";
|
|
7
|
+
import { assertServicePrincipalMayRun, recordServicePrincipalDenial, ServicePrincipalRefusedError, } from "../org/service-principal-guard.js";
|
|
6
8
|
import { readDeployCredentialEnv } from "../server/credential-provider.js";
|
|
7
9
|
import { getH3App } from "../server/framework-request-handler.js";
|
|
8
10
|
import { publicFrameworkPath } from "../server/framework-route-prefix.js";
|
|
@@ -462,7 +464,7 @@ export function mountA2A(nitroApp, config, routePrefix = "/_agent-native") {
|
|
|
462
464
|
}
|
|
463
465
|
catch (err) {
|
|
464
466
|
console.error("[a2a] process-task failed:", err);
|
|
465
|
-
setResponseStatus(event, 500);
|
|
467
|
+
setResponseStatus(event, err instanceof ServicePrincipalRefusedError ? err.statusCode : 500);
|
|
466
468
|
return { error: err?.message ?? "process-task failed" };
|
|
467
469
|
}
|
|
468
470
|
}));
|
|
@@ -480,6 +482,7 @@ export function mountA2A(nitroApp, config, routePrefix = "/_agent-native") {
|
|
|
480
482
|
let verifiedOrgDomain = null;
|
|
481
483
|
let verifiedOrgId;
|
|
482
484
|
let verifiedIdentityAssurance;
|
|
485
|
+
let servicePrincipalAllowedActions;
|
|
483
486
|
let verifiedAudienceBound = false;
|
|
484
487
|
let legacyApiKeyAuthenticated = false;
|
|
485
488
|
let bearerTokenVerified = false;
|
|
@@ -512,6 +515,35 @@ export function mountA2A(nitroApp, config, routePrefix = "/_agent-native") {
|
|
|
512
515
|
},
|
|
513
516
|
};
|
|
514
517
|
}
|
|
518
|
+
try {
|
|
519
|
+
const admission = await assertServicePrincipalMayRun(tokenPayload.email, verifiedOrgId);
|
|
520
|
+
if (parseServiceIdentityEmail(tokenPayload.email)) {
|
|
521
|
+
servicePrincipalAllowedActions = admission.allowedActions;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
catch (error) {
|
|
525
|
+
if (!(error instanceof ServicePrincipalRefusedError))
|
|
526
|
+
throw error;
|
|
527
|
+
if (error.statusCode === 403) {
|
|
528
|
+
await recordServicePrincipalDenial({
|
|
529
|
+
email: tokenPayload.email,
|
|
530
|
+
orgId: verifiedOrgId,
|
|
531
|
+
actionName: "a2a:admission",
|
|
532
|
+
caller: "a2a",
|
|
533
|
+
error,
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
setResponseStatus(event, error.statusCode);
|
|
537
|
+
return {
|
|
538
|
+
jsonrpc: "2.0",
|
|
539
|
+
id: null,
|
|
540
|
+
error: {
|
|
541
|
+
code: error.statusCode === 503 ? -32003 : -32001,
|
|
542
|
+
message: error.message,
|
|
543
|
+
data: { errorCode: error.errorCode },
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
}
|
|
515
547
|
verifiedCallerEmail = tokenPayload.email;
|
|
516
548
|
verifiedOrgDomain = tokenPayload.orgDomain;
|
|
517
549
|
verifiedIdentityAssurance = tokenPayload.email
|
|
@@ -601,6 +633,10 @@ export function mountA2A(nitroApp, config, routePrefix = "/_agent-native") {
|
|
|
601
633
|
if (verifiedOrgId) {
|
|
602
634
|
event.context.__a2aVerifiedOrgId = verifiedOrgId;
|
|
603
635
|
}
|
|
636
|
+
if (servicePrincipalAllowedActions !== undefined) {
|
|
637
|
+
event.context.__a2aServicePrincipalAllowedActions =
|
|
638
|
+
servicePrincipalAllowedActions;
|
|
639
|
+
}
|
|
604
640
|
const body = await readBody(event);
|
|
605
641
|
return handleJsonRpcH3(body, event, config);
|
|
606
642
|
}));
|
package/dist/action.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { normalizeActionChatUIConfig, } from "./action-ui.js";
|
|
2
2
|
import { normalizeAuditConfig, resolveAuditAttach } from "./audit/config.js";
|
|
3
3
|
import { assertRegisteredActionAccess, } from "./authorization/action-access-runtime.js";
|
|
4
|
+
import { parseServiceIdentityEmail } from "./org/service-identity.js";
|
|
4
5
|
import { wrapRunWithActionTracking } from "./tracking/action-lifecycle.js";
|
|
5
6
|
export class ActionContractError extends Error {
|
|
6
7
|
actionContractError = true;
|
|
@@ -136,7 +137,7 @@ export function defineAction(options) {
|
|
|
136
137
|
const finalRun = resolveAuditAttach(auditConfig, readOnly)
|
|
137
138
|
? wrapRunWithAudit(run, auditConfig)
|
|
138
139
|
: run;
|
|
139
|
-
const trackedRun = wrapRunWithActionTracking(finalRun, readOnly);
|
|
140
|
+
const trackedRun = wrapRunWithServicePrincipalGrant(wrapRunWithActionTracking(finalRun, readOnly));
|
|
140
141
|
const toolCallable = typeof options.toolCallable === "boolean"
|
|
141
142
|
? options.toolCallable
|
|
142
143
|
: undefined;
|
|
@@ -302,6 +303,26 @@ function wrapRunWithAccess(run, access, authorize) {
|
|
|
302
303
|
return run(args, ctx);
|
|
303
304
|
};
|
|
304
305
|
}
|
|
306
|
+
/**
|
|
307
|
+
* Outermost wrapper, so a refused call is audited once as a denial and never
|
|
308
|
+
* as a failed run of the action. Every route to running an action as a service
|
|
309
|
+
* identity (MCP, HTTP, delegated agent runs, sandbox bridges) passes here.
|
|
310
|
+
*/
|
|
311
|
+
function wrapRunWithServicePrincipalGrant(run) {
|
|
312
|
+
return function grantCheckedRun(args, ctx) {
|
|
313
|
+
if (!parseServiceIdentityEmail(ctx?.userEmail))
|
|
314
|
+
return run(args, ctx);
|
|
315
|
+
return import("./org/service-principal-guard.js")
|
|
316
|
+
.then(({ enforceServicePrincipalActionGrant }) => enforceServicePrincipalActionGrant({
|
|
317
|
+
email: ctx.userEmail,
|
|
318
|
+
orgId: ctx.orgId,
|
|
319
|
+
// A missing name only passes an unrestricted grant.
|
|
320
|
+
actionName: ctx.actionName ?? "",
|
|
321
|
+
caller: ctx.caller,
|
|
322
|
+
}))
|
|
323
|
+
.then(() => run(args, ctx));
|
|
324
|
+
};
|
|
325
|
+
}
|
|
305
326
|
function wrapRunWithAudit(run, auditConfig) {
|
|
306
327
|
return async function auditedRun(args, ctx) {
|
|
307
328
|
let result;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Terminal reason recorded on the aborted runs; the client shows it as a stopped run. */
|
|
2
|
+
export declare const PRINCIPAL_SUSPENDED_ABORT_REASON = "principal-suspended";
|
|
3
|
+
export interface ContainmentResult {
|
|
4
|
+
abortedRuns: number;
|
|
5
|
+
/** One entry per run that could not be confirmed stopped. Empty means contained. */
|
|
6
|
+
containmentErrors: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function prepareServicePrincipalContainment(): Promise<void>;
|
|
9
|
+
export declare function containServicePrincipal(orgId: string, serviceName: string, reason?: string): Promise<ContainmentResult>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stop the in-flight agent runs a service principal owns.
|
|
3
|
+
*
|
|
4
|
+
* Suspending a principal blocks NEW work at admission, but a run that started
|
|
5
|
+
* before the suspend keeps spending its tool budget until it ends. Containment
|
|
6
|
+
* aborts those runs so "suspended" means stopped, not "stops eventually".
|
|
7
|
+
*
|
|
8
|
+
* A run's owner is its chat thread's `owner_email`. `abortRunDurably` logs and
|
|
9
|
+
* swallows a failed SQL write, so the outcome is re-read from `agent_runs`:
|
|
10
|
+
* only a confirmed `aborted` status counts as aborted.
|
|
11
|
+
*/
|
|
12
|
+
import { ensureChatThreadTables } from "../chat-threads/store.js";
|
|
13
|
+
import { getDbExec } from "../db/client.js";
|
|
14
|
+
import { serviceIdentityEmail } from "../mcp/connect-store.js";
|
|
15
|
+
import { abortRunDurably } from "./run-manager.js";
|
|
16
|
+
import { ensureRunTables, getRunStatus } from "./run-store.js";
|
|
17
|
+
/** Terminal reason recorded on the aborted runs; the client shows it as a stopped run. */
|
|
18
|
+
export const PRINCIPAL_SUSPENDED_ABORT_REASON = "principal-suspended";
|
|
19
|
+
export async function prepareServicePrincipalContainment() {
|
|
20
|
+
await ensureRunTables();
|
|
21
|
+
await ensureChatThreadTables();
|
|
22
|
+
}
|
|
23
|
+
export async function containServicePrincipal(orgId, serviceName, reason = PRINCIPAL_SUSPENDED_ABORT_REASON) {
|
|
24
|
+
const email = serviceIdentityEmail(serviceName, orgId).toLowerCase();
|
|
25
|
+
await prepareServicePrincipalContainment();
|
|
26
|
+
const { rows } = await getDbExec().execute({
|
|
27
|
+
sql: `SELECT r.id FROM agent_runs r
|
|
28
|
+
JOIN chat_threads t ON t.id = r.thread_id
|
|
29
|
+
WHERE r.status = 'running' AND LOWER(t.owner_email) = ?`,
|
|
30
|
+
args: [email],
|
|
31
|
+
});
|
|
32
|
+
const result = { abortedRuns: 0, containmentErrors: [] };
|
|
33
|
+
for (const row of rows) {
|
|
34
|
+
const runId = String(row.id);
|
|
35
|
+
try {
|
|
36
|
+
await abortRunDurably(runId, reason);
|
|
37
|
+
const status = await getRunStatus(runId);
|
|
38
|
+
if (status === "aborted") {
|
|
39
|
+
result.abortedRuns += 1;
|
|
40
|
+
}
|
|
41
|
+
else if (status === "running") {
|
|
42
|
+
result.containmentErrors.push(`${runId}: still running after abort`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
result.containmentErrors.push(`${runId}: ${status ?? "unknown"} after abort; not confirmed aborted`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
result.containmentErrors.push(`${runId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
@@ -24,6 +24,8 @@ import { isMcpToolAllowedForRequest } from "../mcp-client/visibility.js";
|
|
|
24
24
|
import { isObjectOnly } from "../mcp/tool-input-schema.js";
|
|
25
25
|
import { describeSettingsViewForAgent, SETTINGS_VIEW_STATE_KEY, } from "../navigation/settings-redirects.js";
|
|
26
26
|
import { shouldInferSentimentForTurn } from "../observability/sentiment.js";
|
|
27
|
+
import { parseServiceIdentityEmail } from "../org/service-identity.js";
|
|
28
|
+
import { ServicePrincipalRefusedError } from "../org/service-principal-guard.js";
|
|
27
29
|
import { completeRun as completeProgressRun, startRun as startProgressRun, updateRunProgress, } from "../progress/registry.js";
|
|
28
30
|
import { readOptionalKeyCache, writeOptionalKeyCache, } from "../secrets/optional-key-cache.js";
|
|
29
31
|
import { COMPACT_PROMPT_RESOURCES_TOTAL_MAX_CHARS, preloadJevContextForPrompt, } from "../server/agent-chat/prompt-resources.js";
|
|
@@ -4696,6 +4698,28 @@ export async function runAgentLoop(opts) {
|
|
|
4696
4698
|
isError: true,
|
|
4697
4699
|
};
|
|
4698
4700
|
}
|
|
4701
|
+
// Before approval, so a human is never asked to approve a call the
|
|
4702
|
+
// principal's grant already forbids. Covers framework tools that bypass
|
|
4703
|
+
// `defineAction`, which enforces the same grant for the actions.
|
|
4704
|
+
const userEmail = opts.ownerEmail ?? getRequestUserEmail();
|
|
4705
|
+
if (parseServiceIdentityEmail(userEmail)) {
|
|
4706
|
+
const { enforceServicePrincipalActionGrant, ServicePrincipalRefusedError, } = await import("../org/service-principal-guard.js");
|
|
4707
|
+
try {
|
|
4708
|
+
await enforceServicePrincipalActionGrant({
|
|
4709
|
+
email: userEmail,
|
|
4710
|
+
orgId: opts.orgId ?? getRequestOrgId() ?? null,
|
|
4711
|
+
actionName: toolCall.name,
|
|
4712
|
+
caller: opts.actionCaller ?? "tool",
|
|
4713
|
+
});
|
|
4714
|
+
}
|
|
4715
|
+
catch (error) {
|
|
4716
|
+
if (!(error instanceof ServicePrincipalRefusedError) ||
|
|
4717
|
+
error.statusCode !== 403) {
|
|
4718
|
+
throw error;
|
|
4719
|
+
}
|
|
4720
|
+
return declineToolCall(error.message);
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4699
4723
|
const approvalKey = toolCallCacheKey(toolCall.name, toolCall.input);
|
|
4700
4724
|
const approvalBinding = {
|
|
4701
4725
|
toolName: toolCall.name,
|
|
@@ -6401,7 +6425,8 @@ export async function chainServerDrivenContinuation(opts) {
|
|
|
6401
6425
|
}
|
|
6402
6426
|
catch (insertErr) {
|
|
6403
6427
|
if (insertErr instanceof AgentTurnInitiatorMismatchError ||
|
|
6404
|
-
insertErr instanceof AgentTurnInitiatorUnavailableError
|
|
6428
|
+
insertErr instanceof AgentTurnInitiatorUnavailableError ||
|
|
6429
|
+
insertErr instanceof ServicePrincipalRefusedError) {
|
|
6405
6430
|
throw insertErr;
|
|
6406
6431
|
}
|
|
6407
6432
|
await d
|
|
@@ -7785,6 +7810,8 @@ export function createProductionAgentHandler(options) {
|
|
|
7785
7810
|
backgroundRowInserted = true;
|
|
7786
7811
|
}
|
|
7787
7812
|
catch (err) {
|
|
7813
|
+
if (err instanceof ServicePrincipalRefusedError)
|
|
7814
|
+
throw err;
|
|
7788
7815
|
console.error("[agent-chat] background insertRun failed; falling back to inline:", err instanceof Error ? err.message : err);
|
|
7789
7816
|
}
|
|
7790
7817
|
}
|
|
@@ -8042,7 +8069,10 @@ export function createProductionAgentHandler(options) {
|
|
|
8042
8069
|
await insertRun(runId, effectiveThreadId, effectiveTurnId, {
|
|
8043
8070
|
dispatchMode: "background",
|
|
8044
8071
|
...(turnInitiator ? { turnInitiator } : {}),
|
|
8045
|
-
}).catch(() => {
|
|
8072
|
+
}).catch((error) => {
|
|
8073
|
+
if (error instanceof ServicePrincipalRefusedError)
|
|
8074
|
+
throw error;
|
|
8075
|
+
});
|
|
8046
8076
|
}
|
|
8047
8077
|
const won = await claimBackgroundRun(runId);
|
|
8048
8078
|
if (!won) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getAppConfig } from "../app-config/index.js";
|
|
2
2
|
import { BACKGROUND_AUTOMATION_SOFT_TIMEOUT_HEADROOM_MS, BACKGROUND_SOFT_TIMEOUT_CEILING_MS, RUN_NO_PROGRESS_HARD_TIMEOUT_MS, } from "../app-config/run-lifecycle-invariants.js";
|
|
3
3
|
import { recordAgentRun } from "../observability/metrics.js";
|
|
4
|
+
import { parseServiceIdentityEmail } from "../org/service-identity.js";
|
|
5
|
+
import { ServicePrincipalRefusedError } from "../org/service-principal-guard.js";
|
|
4
6
|
import { captureError } from "../server/capture-error.js";
|
|
5
7
|
import { isLlmCredentialError, LLM_MISSING_CREDENTIALS_ERROR_CODE, LLM_MISSING_CREDENTIALS_MESSAGE, } from "./engine/credential-errors.js";
|
|
6
8
|
import { classifyTerminalErrorCode, describeErrorWithCauses, isProviderConnectionError, } from "./engine/error-detail.js";
|
|
@@ -556,12 +558,16 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
556
558
|
: {}),
|
|
557
559
|
}
|
|
558
560
|
: undefined;
|
|
559
|
-
const
|
|
561
|
+
const servicePrincipalRunStart = Boolean(options?.turnInitiator &&
|
|
562
|
+
parseServiceIdentityEmail(options.turnInitiator.email));
|
|
563
|
+
const insertRunPromise = (options?.runRowAlreadyInserted && !servicePrincipalRunStart
|
|
560
564
|
? Promise.resolve()
|
|
561
565
|
: insertOptions
|
|
562
566
|
? insertRun(runId, threadId, options?.turnId, insertOptions)
|
|
563
567
|
: insertRun(runId, threadId, options?.turnId)).catch((error) => {
|
|
564
568
|
captureRunPersistenceError(error, "insert-run");
|
|
569
|
+
if (error instanceof ServicePrincipalRefusedError)
|
|
570
|
+
throw error;
|
|
565
571
|
});
|
|
566
572
|
let persistenceChain = Promise.resolve();
|
|
567
573
|
const PROGRESS_BUMP_INTERVAL_MS = 1_000;
|
|
@@ -1068,7 +1074,13 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1068
1074
|
}
|
|
1069
1075
|
void emitRunEvent(runEvent);
|
|
1070
1076
|
};
|
|
1071
|
-
const runPromise =
|
|
1077
|
+
const runPromise = (servicePrincipalRunStart
|
|
1078
|
+
? insertRunPromise.then(() => {
|
|
1079
|
+
if (!abort.signal.aborted) {
|
|
1080
|
+
return runFn(send, runControl.chunkSignal, runControl);
|
|
1081
|
+
}
|
|
1082
|
+
})
|
|
1083
|
+
: runFn(send, runControl.chunkSignal, runControl))
|
|
1072
1084
|
.then(() => {
|
|
1073
1085
|
settleBoundary(false);
|
|
1074
1086
|
if (abort.signal.aborted) {
|
package/dist/agent/run-store.js
CHANGED
|
@@ -3,6 +3,7 @@ import { isArtifactReceipt, } from "../artifacts/detect.js";
|
|
|
3
3
|
import { getDbExec } from "../db/client.js";
|
|
4
4
|
import { ensureColumnExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
5
5
|
import { widenIntColumnsToBigInt } from "../db/widen-columns.js";
|
|
6
|
+
import { lockAndAssertServicePrincipalMayStartRun, prepareServicePrincipalRunStart, recordServicePrincipalDenial, } from "../org/service-principal-guard.js";
|
|
6
7
|
import { captureError } from "../server/capture-error.js";
|
|
7
8
|
import { isRequestedStopAbortReason } from "./abort-reasons.js";
|
|
8
9
|
import { admitAutoContinue, } from "./auto-continue.js";
|
|
@@ -435,11 +436,34 @@ export async function insertRun(id, threadId, turnId, options) {
|
|
|
435
436
|
(await nextContinuationOrder(client, threadId, logicalTurnId)));
|
|
436
437
|
return;
|
|
437
438
|
}
|
|
438
|
-
|
|
439
|
+
if (options?.turnInitiator) {
|
|
440
|
+
await prepareServicePrincipalRunStart(options.turnInitiator);
|
|
441
|
+
}
|
|
442
|
+
const refusal = await client.transaction(async (tx) => {
|
|
443
|
+
if (options?.turnInitiator) {
|
|
444
|
+
const denied = await lockAndAssertServicePrincipalMayStartRun(tx, {
|
|
445
|
+
email: options.turnInitiator.email,
|
|
446
|
+
orgId: options.turnInitiator.orgId,
|
|
447
|
+
});
|
|
448
|
+
if (denied)
|
|
449
|
+
return denied;
|
|
450
|
+
}
|
|
439
451
|
await lockContinuationOrder(tx, threadId, logicalTurnId);
|
|
440
452
|
await insert(tx, explicitContinuationOrder ??
|
|
441
453
|
(await nextContinuationOrder(tx, threadId, logicalTurnId)));
|
|
454
|
+
return undefined;
|
|
442
455
|
});
|
|
456
|
+
if (refusal) {
|
|
457
|
+
if (options?.turnInitiator) {
|
|
458
|
+
await recordServicePrincipalDenial({
|
|
459
|
+
...options.turnInitiator,
|
|
460
|
+
actionName: "agent-run:start",
|
|
461
|
+
caller: "agent-run",
|
|
462
|
+
error: refusal,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
throw refusal;
|
|
466
|
+
}
|
|
443
467
|
}
|
|
444
468
|
function normalizeContinuationOrder(value) {
|
|
445
469
|
if (value === undefined)
|
|
@@ -790,7 +814,18 @@ export async function tryClaimRunSlot(threadId, runId, maxStaleMs, options) {
|
|
|
790
814
|
if (!client.transaction) {
|
|
791
815
|
throw new Error("Atomic run-slot claims require transaction support");
|
|
792
816
|
}
|
|
793
|
-
|
|
817
|
+
if (options?.turnInitiator) {
|
|
818
|
+
await prepareServicePrincipalRunStart(options.turnInitiator);
|
|
819
|
+
}
|
|
820
|
+
const transactionResult = await client.transaction(async (tx) => {
|
|
821
|
+
if (options?.turnInitiator) {
|
|
822
|
+
const denied = await lockAndAssertServicePrincipalMayStartRun(tx, {
|
|
823
|
+
email: options.turnInitiator.email,
|
|
824
|
+
orgId: options.turnInitiator.orgId,
|
|
825
|
+
});
|
|
826
|
+
if (denied)
|
|
827
|
+
return { refused: denied };
|
|
828
|
+
}
|
|
794
829
|
await tx.execute({
|
|
795
830
|
sql: "SELECT pg_advisory_xact_lock(hashtextextended(?, 0::bigint))",
|
|
796
831
|
args: [`agent-native:run-slot:${threadId}`],
|
|
@@ -801,14 +836,17 @@ export async function tryClaimRunSlot(threadId, runId, maxStaleMs, options) {
|
|
|
801
836
|
args: [threadId, turnId],
|
|
802
837
|
});
|
|
803
838
|
if (abortMarker.rows.length > 0) {
|
|
804
|
-
return {
|
|
839
|
+
return {
|
|
840
|
+
result: { claimed: false, activeRunId: null, turnAborted: true },
|
|
841
|
+
};
|
|
805
842
|
}
|
|
806
843
|
if (options?.turnInitiator) {
|
|
807
844
|
await bindTurnInitiator(tx, threadId, turnId, runId, options.turnInitiator);
|
|
808
845
|
}
|
|
809
846
|
const activeRunId = await selectSlotHoldingRunId(tx, threadId, now, maxStaleMs);
|
|
810
|
-
if (activeRunId)
|
|
811
|
-
return { claimed: false, activeRunId };
|
|
847
|
+
if (activeRunId) {
|
|
848
|
+
return { result: { claimed: false, activeRunId } };
|
|
849
|
+
}
|
|
812
850
|
if (replayCompletedTurn) {
|
|
813
851
|
const latest = await tx.execute({
|
|
814
852
|
sql: `SELECT id,
|
|
@@ -837,9 +875,11 @@ export async function tryClaimRunSlot(threadId, runId, maxStaleMs, options) {
|
|
|
837
875
|
const latestRun = latest.rows[0];
|
|
838
876
|
if (latestRun?.id && latestRun.has_terminal_event === true) {
|
|
839
877
|
return {
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
878
|
+
result: {
|
|
879
|
+
claimed: false,
|
|
880
|
+
activeRunId: null,
|
|
881
|
+
completedRunId: latestRun.id,
|
|
882
|
+
},
|
|
843
883
|
};
|
|
844
884
|
}
|
|
845
885
|
}
|
|
@@ -875,9 +915,11 @@ export async function tryClaimRunSlot(threadId, runId, maxStaleMs, options) {
|
|
|
875
915
|
});
|
|
876
916
|
if (!admission.admit) {
|
|
877
917
|
return {
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
918
|
+
result: {
|
|
919
|
+
claimed: false,
|
|
920
|
+
activeRunId: null,
|
|
921
|
+
autoContinueRefused: admission.code,
|
|
922
|
+
},
|
|
881
923
|
};
|
|
882
924
|
}
|
|
883
925
|
}
|
|
@@ -901,8 +943,20 @@ export async function tryClaimRunSlot(threadId, runId, maxStaleMs, options) {
|
|
|
901
943
|
if ((inserted.rowsAffected ?? 0) !== 1) {
|
|
902
944
|
throw new Error(`Failed to insert claimed run ${runId}`);
|
|
903
945
|
}
|
|
904
|
-
return { claimed: true, activeRunId: null };
|
|
946
|
+
return { result: { claimed: true, activeRunId: null } };
|
|
905
947
|
});
|
|
948
|
+
if ("refused" in transactionResult && transactionResult.refused) {
|
|
949
|
+
if (options?.turnInitiator) {
|
|
950
|
+
await recordServicePrincipalDenial({
|
|
951
|
+
...options.turnInitiator,
|
|
952
|
+
actionName: "agent-run:start",
|
|
953
|
+
caller: "agent-run",
|
|
954
|
+
error: transactionResult.refused,
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
throw transactionResult.refused;
|
|
958
|
+
}
|
|
959
|
+
return transactionResult.result;
|
|
906
960
|
}
|
|
907
961
|
export async function setRunError(runId, errorCode, errorDetail) {
|
|
908
962
|
if (!errorCode && !errorDetail)
|
|
@@ -9,6 +9,7 @@ export declare function projectRootAssistantMessages(input: {
|
|
|
9
9
|
}): {
|
|
10
10
|
representedRootMessageIds: Set<string>;
|
|
11
11
|
snapshotMessageIdsByRootMessageId: Map<string, string>;
|
|
12
|
+
snapshotRunIdsByMessageId: Map<string, string>;
|
|
12
13
|
};
|
|
13
14
|
/** Root assistant IDs represented by the AgentKit snapshot. */
|
|
14
15
|
export declare function representedRootAssistantMessageIds(input: {
|
|
@@ -80,11 +80,13 @@ function eventMessageIdsByRun(runIdsByMessageId) {
|
|
|
80
80
|
}
|
|
81
81
|
return result;
|
|
82
82
|
}
|
|
83
|
-
function assistantRunId(value, runIdsByMessageId) {
|
|
83
|
+
function assistantRunId(value, runIdsByMessageId, inferredRunId) {
|
|
84
84
|
if (value.role !== "assistant")
|
|
85
85
|
return undefined;
|
|
86
86
|
const eventRunIds = typeof value.id === "string" ? runIdsByMessageId.get(value.id) : undefined;
|
|
87
|
-
return eventRunIds?.size === 1 ? [...eventRunIds][0] :
|
|
87
|
+
return ((eventRunIds?.size === 1 ? [...eventRunIds][0] : undefined) ??
|
|
88
|
+
explicitRunId(value) ??
|
|
89
|
+
(eventRunIds?.size ? undefined : inferredRunId));
|
|
88
90
|
}
|
|
89
91
|
function text(value, ignoreNonTextParts = false) {
|
|
90
92
|
if (value.role !== "assistant")
|
|
@@ -231,11 +233,57 @@ export function projectRootAssistantMessages(input) {
|
|
|
231
233
|
: [];
|
|
232
234
|
const runIdsByMessageId = eventRunIds(input.events, input.runs);
|
|
233
235
|
const messageIdsByRun = eventMessageIdsByRun(runIdsByMessageId);
|
|
236
|
+
const snapshotUserIdsByRun = new Map();
|
|
237
|
+
for (const root of rootMessages) {
|
|
238
|
+
if (root.role !== "user")
|
|
239
|
+
continue;
|
|
240
|
+
const custom = record(record(root.metadata)?.custom);
|
|
241
|
+
const snapshotId = typeof custom?.agentKitMessageId === "string"
|
|
242
|
+
? custom.agentKitMessageId
|
|
243
|
+
: typeof root.id === "string"
|
|
244
|
+
? root.id
|
|
245
|
+
: undefined;
|
|
246
|
+
const runId = custom?.submittedRunId;
|
|
247
|
+
if (!snapshotId || typeof runId !== "string")
|
|
248
|
+
continue;
|
|
249
|
+
snapshotUserIdsByRun.set(snapshotId, snapshotUserIdsByRun.has(snapshotId) ? null : runId);
|
|
250
|
+
}
|
|
251
|
+
const snapshotUserCounts = new Map();
|
|
252
|
+
for (const candidate of snapshotMessages) {
|
|
253
|
+
if (candidate.role !== "user" || typeof candidate.id !== "string")
|
|
254
|
+
continue;
|
|
255
|
+
snapshotUserCounts.set(candidate.id, (snapshotUserCounts.get(candidate.id) ?? 0) + 1);
|
|
256
|
+
}
|
|
257
|
+
for (const [snapshotId, runId] of snapshotUserIdsByRun) {
|
|
258
|
+
if (snapshotUserCounts.get(snapshotId) !== 1 || runId === null) {
|
|
259
|
+
snapshotUserIdsByRun.delete(snapshotId);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
234
262
|
const snapshotMessagesByRunId = new Map();
|
|
263
|
+
const snapshotRunIdsByMessageId = new Map();
|
|
264
|
+
let submittedRunId;
|
|
235
265
|
for (const candidate of snapshotMessages) {
|
|
236
|
-
|
|
237
|
-
|
|
266
|
+
if (candidate.role === "user") {
|
|
267
|
+
const candidateRunId = typeof candidate.id === "string"
|
|
268
|
+
? snapshotUserIdsByRun.get(candidate.id)
|
|
269
|
+
: undefined;
|
|
270
|
+
submittedRunId =
|
|
271
|
+
typeof candidateRunId === "string" ? candidateRunId : undefined;
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (candidate.role !== "assistant")
|
|
275
|
+
continue;
|
|
276
|
+
const eventRunIds = typeof candidate.id === "string"
|
|
277
|
+
? runIdsByMessageId.get(candidate.id)
|
|
278
|
+
: undefined;
|
|
279
|
+
const inferredRunId = !eventRunIds?.size && !explicitRunId(candidate)
|
|
280
|
+
? submittedRunId
|
|
281
|
+
: undefined;
|
|
282
|
+
const runId = assistantRunId(candidate, runIdsByMessageId, inferredRunId);
|
|
283
|
+
if (!runId || typeof candidate.id !== "string")
|
|
238
284
|
continue;
|
|
285
|
+
if (inferredRunId)
|
|
286
|
+
snapshotRunIdsByMessageId.set(candidate.id, runId);
|
|
239
287
|
const candidates = snapshotMessagesByRunId.get(runId);
|
|
240
288
|
if (candidates)
|
|
241
289
|
candidates.push(candidate);
|
|
@@ -261,8 +309,9 @@ export function projectRootAssistantMessages(input) {
|
|
|
261
309
|
const clientCanMatchPartial = matchingCandidate !== undefined &&
|
|
262
310
|
(explicitRunId(matchingCandidate) === runId ||
|
|
263
311
|
(typeof matchingCandidate.id === "string" &&
|
|
264
|
-
|
|
265
|
-
|
|
312
|
+
(snapshotRunIdsByMessageId.get(matchingCandidate.id) === runId ||
|
|
313
|
+
(runIdsByMessageId.get(matchingCandidate.id)?.size === 1 &&
|
|
314
|
+
messageIdsByRun.get(runId)?.size === 1))));
|
|
266
315
|
if (sameRunMatches.length === 1 &&
|
|
267
316
|
(exactTextMatch ||
|
|
268
317
|
(sameRunCandidates.length === 1 && clientCanMatchPartial))) {
|
|
@@ -292,6 +341,7 @@ export function projectRootAssistantMessages(input) {
|
|
|
292
341
|
return {
|
|
293
342
|
representedRootMessageIds: represented,
|
|
294
343
|
snapshotMessageIdsByRootMessageId,
|
|
344
|
+
snapshotRunIdsByMessageId,
|
|
295
345
|
};
|
|
296
346
|
}
|
|
297
347
|
/** Root assistant IDs represented by the AgentKit snapshot. */
|
|
@@ -2,7 +2,7 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
2
2
|
scope?: "accessible" | "organization";
|
|
3
3
|
targetType?: string;
|
|
4
4
|
targetId?: string;
|
|
5
|
-
actorKind?: "agent" | "human" | "system";
|
|
5
|
+
actorKind?: "agent" | "human" | "service" | "system";
|
|
6
6
|
actorEmail?: string;
|
|
7
7
|
status?: "denied" | "error" | "success";
|
|
8
8
|
threadId?: string;
|
|
@@ -56,9 +56,9 @@ export default defineAction({
|
|
|
56
56
|
.optional()
|
|
57
57
|
.describe("Filter to one resource id (pair with targetType)."),
|
|
58
58
|
actorKind: z
|
|
59
|
-
.enum(["agent", "human", "system"])
|
|
59
|
+
.enum(["agent", "human", "service", "system"])
|
|
60
60
|
.optional()
|
|
61
|
-
.describe("Filter to changes made by
|
|
61
|
+
.describe("Filter to changes made by an agent, human, service principal, or the system."),
|
|
62
62
|
actorEmail: z.string().optional().describe("Filter to one actor's email."),
|
|
63
63
|
status: z
|
|
64
64
|
.enum(["success", "error", "denied"])
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare const _default: import("../../action.js").ActionDefinition<{
|
|
2
|
+
since?: string | number;
|
|
3
|
+
until?: string | number;
|
|
4
|
+
cursor?: string;
|
|
5
|
+
limit?: number;
|
|
6
|
+
}, {
|
|
7
|
+
events: import("../ocsf.js").OcsfApiActivity[];
|
|
8
|
+
hasMore: boolean;
|
|
9
|
+
nextCursor: string;
|
|
10
|
+
}>;
|
|
11
|
+
export default _default;
|