@openbox-ai/openbox-mastra-sdk 0.1.0
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/LICENSE +21 -0
- package/README.md +158 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/openbox-client.d.ts +42 -0
- package/dist/client/openbox-client.js +405 -0
- package/dist/client/openbox-client.js.map +1 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/openbox-config.d.ts +54 -0
- package/dist/config/openbox-config.js +162 -0
- package/dist/config/openbox-config.js.map +1 -0
- package/dist/governance/activity-runtime.d.ts +42 -0
- package/dist/governance/activity-runtime.js +712 -0
- package/dist/governance/activity-runtime.js.map +1 -0
- package/dist/governance/approval-registry.d.ts +17 -0
- package/dist/governance/approval-registry.js +32 -0
- package/dist/governance/approval-registry.js.map +1 -0
- package/dist/governance/context.d.ts +16 -0
- package/dist/governance/context.js +13 -0
- package/dist/governance/context.js.map +1 -0
- package/dist/governance/index.d.ts +2 -0
- package/dist/governance/index.js +1 -0
- package/dist/governance/index.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/mastra/index.d.ts +16 -0
- package/dist/mastra/index.js +5 -0
- package/dist/mastra/index.js.map +1 -0
- package/dist/mastra/with-openbox.d.ts +30 -0
- package/dist/mastra/with-openbox.js +243 -0
- package/dist/mastra/with-openbox.js.map +1 -0
- package/dist/mastra/wrap-agent.d.ts +14 -0
- package/dist/mastra/wrap-agent.js +1744 -0
- package/dist/mastra/wrap-agent.js.map +1 -0
- package/dist/mastra/wrap-tool.d.ts +18 -0
- package/dist/mastra/wrap-tool.js +49 -0
- package/dist/mastra/wrap-tool.js.map +1 -0
- package/dist/mastra/wrap-workflow.d.ts +14 -0
- package/dist/mastra/wrap-workflow.js +386 -0
- package/dist/mastra/wrap-workflow.js.map +1 -0
- package/dist/otel/index.d.ts +11 -0
- package/dist/otel/index.js +2 -0
- package/dist/otel/index.js.map +1 -0
- package/dist/otel/setup-openbox-opentelemetry.d.ts +38 -0
- package/dist/otel/setup-openbox-opentelemetry.js +2249 -0
- package/dist/otel/setup-openbox-opentelemetry.js.map +1 -0
- package/dist/span/index.d.ts +5 -0
- package/dist/span/index.js +2 -0
- package/dist/span/index.js.map +1 -0
- package/dist/span/openbox-span-processor.d.ts +90 -0
- package/dist/span/openbox-span-processor.js +580 -0
- package/dist/span/openbox-span-processor.js.map +1 -0
- package/dist/types/errors.d.ts +25 -0
- package/dist/types/errors.js +40 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/governance-verdict-response.d.ts +57 -0
- package/dist/types/governance-verdict-response.js +84 -0
- package/dist/types/governance-verdict-response.js.map +1 -0
- package/dist/types/guardrails.d.ts +23 -0
- package/dist/types/guardrails.js +27 -0
- package/dist/types/guardrails.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/verdict.d.ts +22 -0
- package/dist/types/verdict.js +55 -0
- package/dist/types/verdict.js.map +1 -0
- package/dist/types/workflow-event-type.d.ts +10 -0
- package/dist/types/workflow-event-type.js +13 -0
- package/dist/types/workflow-event-type.js.map +1 -0
- package/dist/types/workflow-span-buffer.d.ts +31 -0
- package/dist/types/workflow-span-buffer.js +42 -0
- package/dist/types/workflow-span-buffer.js.map +1 -0
- package/docs/README.md +66 -0
- package/docs/api-reference.md +348 -0
- package/docs/approvals-and-guardrails.md +163 -0
- package/docs/architecture.md +186 -0
- package/docs/configuration.md +214 -0
- package/docs/event-model.md +215 -0
- package/docs/installation.md +108 -0
- package/docs/integration-patterns.md +214 -0
- package/docs/security-and-privacy.md +174 -0
- package/docs/telemetry.md +196 -0
- package/docs/troubleshooting.md +210 -0
- package/package.json +136 -0
|
@@ -0,0 +1,712 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { trace } from "@opentelemetry/api";
|
|
3
|
+
import {
|
|
4
|
+
ApprovalExpiredError,
|
|
5
|
+
ApprovalPendingError,
|
|
6
|
+
ApprovalRejectedError,
|
|
7
|
+
GovernanceVerdictResponse,
|
|
8
|
+
GovernanceHaltError,
|
|
9
|
+
GuardrailsValidationError,
|
|
10
|
+
Verdict,
|
|
11
|
+
WorkflowEventType,
|
|
12
|
+
WorkflowSpanBuffer
|
|
13
|
+
} from "../types/index.js";
|
|
14
|
+
import {
|
|
15
|
+
getOpenBoxExecutionContext,
|
|
16
|
+
runWithOpenBoxExecutionContext
|
|
17
|
+
} from "./context.js";
|
|
18
|
+
import {
|
|
19
|
+
clearActivityApproval,
|
|
20
|
+
clearPendingApproval,
|
|
21
|
+
isActivityApproved,
|
|
22
|
+
markActivityApproved,
|
|
23
|
+
setPendingApproval
|
|
24
|
+
} from "./approval-registry.js";
|
|
25
|
+
async function executeGovernedActivity({
|
|
26
|
+
dependencies,
|
|
27
|
+
execute,
|
|
28
|
+
input,
|
|
29
|
+
runtimeContext,
|
|
30
|
+
type
|
|
31
|
+
}) {
|
|
32
|
+
const descriptor = resolveActivityDescriptor(type, runtimeContext);
|
|
33
|
+
const startedInputForEvent = appendGoalToActivityInput(
|
|
34
|
+
serializeActivityInputForStartEvent(input),
|
|
35
|
+
descriptor.goal
|
|
36
|
+
);
|
|
37
|
+
let inputForExecution = cloneValue(input);
|
|
38
|
+
ensureSpanBuffer(descriptor, dependencies.spanProcessor);
|
|
39
|
+
dependencies.spanProcessor.clearActivityAbort(
|
|
40
|
+
descriptor.workflowId,
|
|
41
|
+
descriptor.activityId
|
|
42
|
+
);
|
|
43
|
+
dependencies.spanProcessor.clearHaltRequested(
|
|
44
|
+
descriptor.workflowId,
|
|
45
|
+
descriptor.activityId
|
|
46
|
+
);
|
|
47
|
+
dependencies.spanProcessor.setActivityContext(
|
|
48
|
+
descriptor.workflowId,
|
|
49
|
+
descriptor.activityId,
|
|
50
|
+
{
|
|
51
|
+
activity_id: descriptor.activityId,
|
|
52
|
+
activity_input: startedInputForEvent,
|
|
53
|
+
activity_type: descriptor.activityType,
|
|
54
|
+
attempt: descriptor.attempt,
|
|
55
|
+
...descriptor.goal ? { goal: descriptor.goal } : {},
|
|
56
|
+
run_id: descriptor.runId,
|
|
57
|
+
task_queue: descriptor.taskQueue,
|
|
58
|
+
workflow_id: descriptor.workflowId,
|
|
59
|
+
workflow_type: descriptor.workflowType
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
const startVerdict = dependencies.config.sendActivityStartEvent ? await evaluateActivityEvent(dependencies, {
|
|
63
|
+
activity_id: descriptor.activityId,
|
|
64
|
+
activity_input: startedInputForEvent,
|
|
65
|
+
activity_type: descriptor.activityType,
|
|
66
|
+
attempt: descriptor.attempt,
|
|
67
|
+
event_type: WorkflowEventType.ACTIVITY_STARTED,
|
|
68
|
+
...descriptor.goal ? { goal: descriptor.goal } : {},
|
|
69
|
+
run_id: descriptor.runId,
|
|
70
|
+
task_queue: descriptor.taskQueue,
|
|
71
|
+
workflow_id: descriptor.workflowId,
|
|
72
|
+
workflow_type: descriptor.workflowType
|
|
73
|
+
}) : null;
|
|
74
|
+
applyStopVerdict(startVerdict);
|
|
75
|
+
assertGuardrailsValid(startVerdict, "Guardrails validation failed");
|
|
76
|
+
if (startVerdict?.guardrailsResult?.inputType === "activity_input" && startVerdict.guardrailsResult.redactedInput !== void 0) {
|
|
77
|
+
const normalizedRedactedInput = normalizeRedactedActivityInput(
|
|
78
|
+
inputForExecution,
|
|
79
|
+
startVerdict.guardrailsResult.redactedInput
|
|
80
|
+
);
|
|
81
|
+
inputForExecution = applyRedaction(
|
|
82
|
+
inputForExecution,
|
|
83
|
+
normalizedRedactedInput
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (dependencies.config.hitlEnabled && Verdict.requiresApproval(startVerdict?.verdict ?? Verdict.ALLOW)) {
|
|
87
|
+
const approvalPayload = {
|
|
88
|
+
openbox: {
|
|
89
|
+
activityId: descriptor.activityId,
|
|
90
|
+
activityType: descriptor.activityType,
|
|
91
|
+
approvalId: startVerdict?.approvalId,
|
|
92
|
+
reason: startVerdict?.reason,
|
|
93
|
+
requestedAt: rfc3339Now(),
|
|
94
|
+
runId: descriptor.runId,
|
|
95
|
+
workflowId: descriptor.workflowId,
|
|
96
|
+
workflowType: descriptor.workflowType
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
setPendingApproval({
|
|
100
|
+
activityId: descriptor.activityId,
|
|
101
|
+
activityType: descriptor.activityType,
|
|
102
|
+
approvalId: startVerdict?.approvalId,
|
|
103
|
+
requestedAt: approvalPayload.openbox.requestedAt,
|
|
104
|
+
runId: descriptor.runId,
|
|
105
|
+
workflowId: descriptor.workflowId,
|
|
106
|
+
workflowType: descriptor.workflowType
|
|
107
|
+
});
|
|
108
|
+
const workflowSuspend = runtimeContext.workflow?.suspend;
|
|
109
|
+
if (workflowSuspend) {
|
|
110
|
+
return await workflowSuspend(approvalPayload);
|
|
111
|
+
}
|
|
112
|
+
await waitForApprovalInline(dependencies.client, descriptor, startVerdict?.reason);
|
|
113
|
+
}
|
|
114
|
+
return runWithOpenBoxExecutionContext(
|
|
115
|
+
{
|
|
116
|
+
activityId: descriptor.activityId,
|
|
117
|
+
activityType: descriptor.activityType,
|
|
118
|
+
attempt: descriptor.attempt,
|
|
119
|
+
goal: descriptor.goal,
|
|
120
|
+
runId: descriptor.runId,
|
|
121
|
+
source: "tool",
|
|
122
|
+
taskQueue: descriptor.taskQueue,
|
|
123
|
+
workflowId: descriptor.workflowId,
|
|
124
|
+
workflowType: descriptor.workflowType
|
|
125
|
+
},
|
|
126
|
+
async () => {
|
|
127
|
+
let error;
|
|
128
|
+
let haltReason;
|
|
129
|
+
let output;
|
|
130
|
+
const activityStartMs = Date.now();
|
|
131
|
+
try {
|
|
132
|
+
output = await trace.getTracer("openbox.mastra").startActiveSpan(`activity.${descriptor.activityType}`, async (activeSpan) => {
|
|
133
|
+
activeSpan.setAttribute("openbox.workflow_id", descriptor.workflowId);
|
|
134
|
+
activeSpan.setAttribute("openbox.activity_id", descriptor.activityId);
|
|
135
|
+
activeSpan.setAttribute("openbox.run_id", descriptor.runId);
|
|
136
|
+
dependencies.spanProcessor.registerTrace(
|
|
137
|
+
activeSpan.spanContext().traceId,
|
|
138
|
+
descriptor.workflowId,
|
|
139
|
+
descriptor.activityId,
|
|
140
|
+
descriptor.runId
|
|
141
|
+
);
|
|
142
|
+
try {
|
|
143
|
+
return await execute(inputForExecution);
|
|
144
|
+
} finally {
|
|
145
|
+
activeSpan.end();
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
} catch (caughtError) {
|
|
149
|
+
if (caughtError instanceof ApprovalPendingError && dependencies.config.hitlEnabled) {
|
|
150
|
+
const approvalPayload = {
|
|
151
|
+
openbox: {
|
|
152
|
+
activityId: descriptor.activityId,
|
|
153
|
+
activityType: descriptor.activityType,
|
|
154
|
+
approvalId: void 0,
|
|
155
|
+
reason: caughtError.message,
|
|
156
|
+
requestedAt: rfc3339Now(),
|
|
157
|
+
runId: descriptor.runId,
|
|
158
|
+
workflowId: descriptor.workflowId,
|
|
159
|
+
workflowType: descriptor.workflowType
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
setPendingApproval({
|
|
163
|
+
activityId: descriptor.activityId,
|
|
164
|
+
activityType: descriptor.activityType,
|
|
165
|
+
approvalId: void 0,
|
|
166
|
+
requestedAt: approvalPayload.openbox.requestedAt,
|
|
167
|
+
runId: descriptor.runId,
|
|
168
|
+
workflowId: descriptor.workflowId,
|
|
169
|
+
workflowType: descriptor.workflowType
|
|
170
|
+
});
|
|
171
|
+
const workflowSuspend = runtimeContext.workflow?.suspend;
|
|
172
|
+
if (workflowSuspend) {
|
|
173
|
+
return await workflowSuspend(approvalPayload);
|
|
174
|
+
}
|
|
175
|
+
await waitForApprovalInline(
|
|
176
|
+
dependencies.client,
|
|
177
|
+
descriptor,
|
|
178
|
+
caughtError.message
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
error = serializeError(caughtError);
|
|
182
|
+
throw caughtError;
|
|
183
|
+
} finally {
|
|
184
|
+
try {
|
|
185
|
+
const wasAborted = dependencies.spanProcessor.getActivityAbort(
|
|
186
|
+
descriptor.workflowId,
|
|
187
|
+
descriptor.activityId
|
|
188
|
+
);
|
|
189
|
+
const activityEndMs = Date.now();
|
|
190
|
+
const durationMs = Math.max(0, activityEndMs - activityStartMs);
|
|
191
|
+
const alreadyApproved = isActivityApproved(
|
|
192
|
+
descriptor.runId,
|
|
193
|
+
descriptor.activityId
|
|
194
|
+
);
|
|
195
|
+
if (!wasAborted) {
|
|
196
|
+
const completedInputForEvent = appendGoalToActivityInput(
|
|
197
|
+
serializeActivityInputForCompletedEvent(inputForExecution),
|
|
198
|
+
descriptor.goal
|
|
199
|
+
);
|
|
200
|
+
const completedActivityTypePayload = dependencies.config.hitlEnabled ? {} : { activity_type: descriptor.activityType };
|
|
201
|
+
const completedVerdict = await evaluateActivityEvent(dependencies, {
|
|
202
|
+
activity_id: descriptor.activityId,
|
|
203
|
+
activity_input: completedInputForEvent,
|
|
204
|
+
activity_output: serializeValue(output),
|
|
205
|
+
...completedActivityTypePayload,
|
|
206
|
+
attempt: descriptor.attempt,
|
|
207
|
+
duration_ms: durationMs,
|
|
208
|
+
end_time: activityEndMs,
|
|
209
|
+
error,
|
|
210
|
+
event_type: WorkflowEventType.ACTIVITY_COMPLETED,
|
|
211
|
+
...descriptor.goal ? { goal: descriptor.goal } : {},
|
|
212
|
+
run_id: descriptor.runId,
|
|
213
|
+
span_count: 0,
|
|
214
|
+
start_time: activityStartMs,
|
|
215
|
+
status: error ? "failed" : "completed",
|
|
216
|
+
task_queue: descriptor.taskQueue,
|
|
217
|
+
workflow_id: descriptor.workflowId,
|
|
218
|
+
workflow_type: descriptor.workflowType
|
|
219
|
+
});
|
|
220
|
+
applyStopVerdict(completedVerdict);
|
|
221
|
+
assertGuardrailsValid(
|
|
222
|
+
completedVerdict,
|
|
223
|
+
"Guardrails output validation failed"
|
|
224
|
+
);
|
|
225
|
+
if (completedVerdict?.guardrailsResult?.inputType === "activity_output" && completedVerdict.guardrailsResult.redactedInput !== void 0) {
|
|
226
|
+
output = applyRedaction(
|
|
227
|
+
output,
|
|
228
|
+
completedVerdict.guardrailsResult.redactedInput
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
if (dependencies.config.hitlEnabled && Verdict.requiresApproval(completedVerdict?.verdict ?? Verdict.ALLOW) && !alreadyApproved && !isActivityApproved(descriptor.runId, descriptor.activityId)) {
|
|
232
|
+
const approvalPayload = {
|
|
233
|
+
openbox: {
|
|
234
|
+
activityId: descriptor.activityId,
|
|
235
|
+
activityType: descriptor.activityType,
|
|
236
|
+
approvalId: completedVerdict?.approvalId,
|
|
237
|
+
reason: completedVerdict?.reason,
|
|
238
|
+
requestedAt: rfc3339Now(),
|
|
239
|
+
runId: descriptor.runId,
|
|
240
|
+
workflowId: descriptor.workflowId,
|
|
241
|
+
workflowType: descriptor.workflowType
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
setPendingApproval({
|
|
245
|
+
activityId: descriptor.activityId,
|
|
246
|
+
activityType: descriptor.activityType,
|
|
247
|
+
approvalId: completedVerdict?.approvalId,
|
|
248
|
+
requestedAt: approvalPayload.openbox.requestedAt,
|
|
249
|
+
runId: descriptor.runId,
|
|
250
|
+
workflowId: descriptor.workflowId,
|
|
251
|
+
workflowType: descriptor.workflowType
|
|
252
|
+
});
|
|
253
|
+
const workflowSuspend = runtimeContext.workflow?.suspend;
|
|
254
|
+
if (workflowSuspend) {
|
|
255
|
+
output = await workflowSuspend(approvalPayload);
|
|
256
|
+
} else {
|
|
257
|
+
await waitForApprovalInline(
|
|
258
|
+
dependencies.client,
|
|
259
|
+
descriptor,
|
|
260
|
+
completedVerdict?.reason ?? "Activity output requires human approval"
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
haltReason = dependencies.spanProcessor.getHaltRequested(
|
|
266
|
+
descriptor.workflowId,
|
|
267
|
+
descriptor.activityId
|
|
268
|
+
);
|
|
269
|
+
} finally {
|
|
270
|
+
dependencies.spanProcessor.clearActivityAbort(
|
|
271
|
+
descriptor.workflowId,
|
|
272
|
+
descriptor.activityId
|
|
273
|
+
);
|
|
274
|
+
dependencies.spanProcessor.clearHaltRequested(
|
|
275
|
+
descriptor.workflowId,
|
|
276
|
+
descriptor.activityId
|
|
277
|
+
);
|
|
278
|
+
dependencies.spanProcessor.clearActivityContext(
|
|
279
|
+
descriptor.workflowId,
|
|
280
|
+
descriptor.activityId
|
|
281
|
+
);
|
|
282
|
+
clearActivityApproval(descriptor.runId, descriptor.activityId);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (haltReason) {
|
|
286
|
+
throw new GovernanceHaltError(`Governance blocked: ${haltReason}`);
|
|
287
|
+
}
|
|
288
|
+
return output;
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
const INLINE_APPROVAL_TIMEOUT_MS = 3e5;
|
|
293
|
+
const INLINE_APPROVAL_INITIAL_POLL_INTERVAL_MS = 2500;
|
|
294
|
+
const INLINE_APPROVAL_MAX_POLL_INTERVAL_MS = 15e3;
|
|
295
|
+
const INLINE_APPROVAL_BACKOFF_MULTIPLIER = 2;
|
|
296
|
+
const inflightInlineApprovalWaits = /* @__PURE__ */ new Map();
|
|
297
|
+
async function waitForApprovalInline(client, descriptor, reason) {
|
|
298
|
+
const inflightKey = `${descriptor.runId}::${descriptor.activityId}`;
|
|
299
|
+
const existingWait = inflightInlineApprovalWaits.get(inflightKey);
|
|
300
|
+
if (existingWait) {
|
|
301
|
+
await existingWait;
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const waitPromise = (async () => {
|
|
305
|
+
const timeoutAt = Date.now() + INLINE_APPROVAL_TIMEOUT_MS;
|
|
306
|
+
let pollIntervalMs = INLINE_APPROVAL_INITIAL_POLL_INTERVAL_MS;
|
|
307
|
+
while (Date.now() < timeoutAt) {
|
|
308
|
+
await delay(pollIntervalMs);
|
|
309
|
+
if (Date.now() >= timeoutAt) {
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
const approval = await client.pollApproval({
|
|
313
|
+
activityId: descriptor.activityId,
|
|
314
|
+
runId: descriptor.runId,
|
|
315
|
+
workflowId: descriptor.workflowId
|
|
316
|
+
});
|
|
317
|
+
if (!approval) {
|
|
318
|
+
pollIntervalMs = Math.min(
|
|
319
|
+
INLINE_APPROVAL_MAX_POLL_INTERVAL_MS,
|
|
320
|
+
Math.ceil(pollIntervalMs * INLINE_APPROVAL_BACKOFF_MULTIPLIER)
|
|
321
|
+
);
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (approval.expired) {
|
|
325
|
+
clearPendingApproval(descriptor.runId);
|
|
326
|
+
throw new ApprovalExpiredError(
|
|
327
|
+
`Approval expired for activity ${descriptor.activityType}`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
const verdict = Verdict.fromString(
|
|
331
|
+
approval.verdict ?? approval.action
|
|
332
|
+
);
|
|
333
|
+
if (verdict === Verdict.ALLOW) {
|
|
334
|
+
markActivityApproved(descriptor.runId, descriptor.activityId);
|
|
335
|
+
clearPendingApproval(descriptor.runId);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (Verdict.shouldStop(verdict)) {
|
|
339
|
+
clearPendingApproval(descriptor.runId);
|
|
340
|
+
throw new ApprovalRejectedError(
|
|
341
|
+
`Activity rejected: ${String(approval.reason ?? "Activity rejected")}`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
pollIntervalMs = Math.min(
|
|
345
|
+
INLINE_APPROVAL_MAX_POLL_INTERVAL_MS,
|
|
346
|
+
Math.ceil(pollIntervalMs * INLINE_APPROVAL_BACKOFF_MULTIPLIER)
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
throw new ApprovalPendingError(
|
|
350
|
+
reason ?? `Awaiting approval for activity ${descriptor.activityType}`
|
|
351
|
+
);
|
|
352
|
+
})();
|
|
353
|
+
inflightInlineApprovalWaits.set(inflightKey, waitPromise);
|
|
354
|
+
try {
|
|
355
|
+
await waitPromise;
|
|
356
|
+
} finally {
|
|
357
|
+
inflightInlineApprovalWaits.delete(inflightKey);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async function delay(ms) {
|
|
361
|
+
if (ms <= 0) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
await new Promise((resolve) => {
|
|
365
|
+
setTimeout(resolve, ms);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
function serializeValue(value) {
|
|
369
|
+
if (value == null) {
|
|
370
|
+
return value;
|
|
371
|
+
}
|
|
372
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
373
|
+
return value;
|
|
374
|
+
}
|
|
375
|
+
if (value instanceof Uint8Array) {
|
|
376
|
+
return Buffer.from(value).toString("utf8");
|
|
377
|
+
}
|
|
378
|
+
if (Array.isArray(value)) {
|
|
379
|
+
return value.map((item) => serializeValue(item));
|
|
380
|
+
}
|
|
381
|
+
if (value instanceof Date) {
|
|
382
|
+
return value.toISOString();
|
|
383
|
+
}
|
|
384
|
+
if (typeof value === "object") {
|
|
385
|
+
return Object.fromEntries(
|
|
386
|
+
Object.entries(value).map(([key, entry]) => [
|
|
387
|
+
key,
|
|
388
|
+
serializeValue(entry)
|
|
389
|
+
])
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
return String(value);
|
|
393
|
+
}
|
|
394
|
+
function normalizeSpansForGovernance(spans) {
|
|
395
|
+
return spans.map((span) => normalizeSpanForGovernance(span));
|
|
396
|
+
}
|
|
397
|
+
function serializeActivityInputForStartEvent(value) {
|
|
398
|
+
const serialized = serializeValue(value);
|
|
399
|
+
if (serialized == null) {
|
|
400
|
+
return [];
|
|
401
|
+
}
|
|
402
|
+
return serialized;
|
|
403
|
+
}
|
|
404
|
+
function serializeActivityInputForCompletedEvent(value) {
|
|
405
|
+
const serialized = serializeValue(value);
|
|
406
|
+
if (serialized == null) {
|
|
407
|
+
return [];
|
|
408
|
+
}
|
|
409
|
+
return Array.isArray(serialized) ? serialized : [serialized];
|
|
410
|
+
}
|
|
411
|
+
function appendGoalToActivityInput(activityInput, goal) {
|
|
412
|
+
if (!goal || goal.trim().length === 0) {
|
|
413
|
+
return activityInput;
|
|
414
|
+
}
|
|
415
|
+
const trimmedGoal = goal.trim();
|
|
416
|
+
if (trimmedGoal.length === 0) {
|
|
417
|
+
return activityInput;
|
|
418
|
+
}
|
|
419
|
+
if (Array.isArray(activityInput)) {
|
|
420
|
+
const inputItems = activityInput;
|
|
421
|
+
if (inputItems.length === 0) {
|
|
422
|
+
return [{ goal: trimmedGoal }];
|
|
423
|
+
}
|
|
424
|
+
const [first, ...rest] = inputItems;
|
|
425
|
+
if (first && typeof first === "object" && !Array.isArray(first)) {
|
|
426
|
+
const firstRecord = first;
|
|
427
|
+
const existingGoal = firstRecord.goal;
|
|
428
|
+
if (typeof existingGoal === "string" && existingGoal.trim().length > 0) {
|
|
429
|
+
return inputItems;
|
|
430
|
+
}
|
|
431
|
+
return [{ ...firstRecord, goal: trimmedGoal }, ...rest];
|
|
432
|
+
}
|
|
433
|
+
return [...inputItems, { goal: trimmedGoal }];
|
|
434
|
+
}
|
|
435
|
+
if (activityInput === void 0 || activityInput === null) {
|
|
436
|
+
return [{ goal: trimmedGoal }];
|
|
437
|
+
}
|
|
438
|
+
if (activityInput && typeof activityInput === "object") {
|
|
439
|
+
const activityRecord = activityInput;
|
|
440
|
+
const existingGoal = activityRecord.goal;
|
|
441
|
+
if (typeof existingGoal === "string" && existingGoal.trim().length > 0) {
|
|
442
|
+
return activityInput;
|
|
443
|
+
}
|
|
444
|
+
return {
|
|
445
|
+
...activityRecord,
|
|
446
|
+
goal: trimmedGoal
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
return [activityInput, { goal: trimmedGoal }];
|
|
450
|
+
}
|
|
451
|
+
function normalizeRedactedActivityInput(originalInput, redactedInput) {
|
|
452
|
+
if (!Array.isArray(originalInput) && Array.isArray(redactedInput)) {
|
|
453
|
+
if (redactedInput.length === 0) {
|
|
454
|
+
return redactedInput;
|
|
455
|
+
}
|
|
456
|
+
if (redactedInput.length === 1) {
|
|
457
|
+
return redactedInput[0];
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return redactedInput;
|
|
461
|
+
}
|
|
462
|
+
function applyRedaction(original, redacted) {
|
|
463
|
+
if (original && redacted && typeof original === "object" && typeof redacted === "object" && !Array.isArray(original) && !Array.isArray(redacted)) {
|
|
464
|
+
const updated = {
|
|
465
|
+
...original
|
|
466
|
+
};
|
|
467
|
+
for (const [key, value] of Object.entries(redacted)) {
|
|
468
|
+
updated[key] = applyRedaction(
|
|
469
|
+
original[key],
|
|
470
|
+
value
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
return updated;
|
|
474
|
+
}
|
|
475
|
+
if (Array.isArray(redacted)) {
|
|
476
|
+
return redacted.map(
|
|
477
|
+
(value, index) => applyRedaction(Array.isArray(original) ? original[index] : void 0, value)
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
return cloneValue(redacted);
|
|
481
|
+
}
|
|
482
|
+
function cloneValue(value) {
|
|
483
|
+
if (value === void 0) {
|
|
484
|
+
return value;
|
|
485
|
+
}
|
|
486
|
+
return structuredClone(value);
|
|
487
|
+
}
|
|
488
|
+
function rfc3339Now() {
|
|
489
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
490
|
+
}
|
|
491
|
+
function resolveActivityDescriptor(type, runtimeContext) {
|
|
492
|
+
const normalizedType = normalizeActivityType(type);
|
|
493
|
+
const activeContext = getOpenBoxExecutionContext();
|
|
494
|
+
const runId = runtimeContext.workflow?.runId ?? activeContext?.runId ?? runtimeContext.agent?.toolCallId ?? randomUUID();
|
|
495
|
+
const workflowId = runtimeContext.workflow?.workflowId ?? activeContext?.workflowId ?? `tool:${type}`;
|
|
496
|
+
const workflowType = activeContext?.workflowType ?? workflowId;
|
|
497
|
+
const activityId = runtimeContext.agent?.toolCallId ?? activeContext?.activityId ?? `${workflowId}:${type}`;
|
|
498
|
+
return {
|
|
499
|
+
activityId,
|
|
500
|
+
activityType: normalizedType,
|
|
501
|
+
attempt: activeContext?.attempt ?? 1,
|
|
502
|
+
...activeContext?.goal ? { goal: activeContext.goal } : {},
|
|
503
|
+
runId,
|
|
504
|
+
taskQueue: activeContext?.taskQueue ?? "mastra",
|
|
505
|
+
workflowId,
|
|
506
|
+
workflowType
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
function normalizeActivityType(value) {
|
|
510
|
+
const trimmed = value.trim();
|
|
511
|
+
if (!trimmed) {
|
|
512
|
+
return "activity";
|
|
513
|
+
}
|
|
514
|
+
if (/^[a-z][A-Za-z0-9]*$/.test(trimmed)) {
|
|
515
|
+
return trimmed;
|
|
516
|
+
}
|
|
517
|
+
const tokens = trimmed.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^A-Za-z0-9]+/).filter(Boolean).map((token) => token.toLowerCase());
|
|
518
|
+
if (tokens.length === 0) {
|
|
519
|
+
return "activity";
|
|
520
|
+
}
|
|
521
|
+
const [first, ...rest] = tokens;
|
|
522
|
+
return `${first}${rest.map((token) => token.charAt(0).toUpperCase() + token.slice(1)).join("")}`;
|
|
523
|
+
}
|
|
524
|
+
async function evaluateActivityEvent(dependencies, payload) {
|
|
525
|
+
const body = {
|
|
526
|
+
source: "workflow-telemetry",
|
|
527
|
+
timestamp: rfc3339Now(),
|
|
528
|
+
...payload
|
|
529
|
+
};
|
|
530
|
+
try {
|
|
531
|
+
return await dependencies.client.evaluate(body);
|
|
532
|
+
} catch (error) {
|
|
533
|
+
if (dependencies.config.onApiError === "fail_closed") {
|
|
534
|
+
return new GovernanceVerdictResponse({
|
|
535
|
+
reason: `Governance API error: ${error instanceof Error ? error.message : String(error)}`,
|
|
536
|
+
verdict: Verdict.HALT
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
function applyStopVerdict(verdict) {
|
|
543
|
+
if (verdict && Verdict.shouldStop(verdict.verdict)) {
|
|
544
|
+
throw new GovernanceHaltError(
|
|
545
|
+
`Governance blocked: ${verdict.reason ?? "No reason provided"}`
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
function assertGuardrailsValid(verdict, fallbackMessage) {
|
|
550
|
+
if (!verdict?.guardrailsResult || verdict.guardrailsResult.validationPassed) {
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
const reasons = verdict.guardrailsResult.getReasonStrings();
|
|
554
|
+
const reason = reasons.length > 0 ? reasons.join("; ") : fallbackMessage;
|
|
555
|
+
throw new GuardrailsValidationError(reason);
|
|
556
|
+
}
|
|
557
|
+
function serializeError(error) {
|
|
558
|
+
if (error instanceof Error) {
|
|
559
|
+
return {
|
|
560
|
+
message: error.message,
|
|
561
|
+
type: error.name
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
return {
|
|
565
|
+
message: String(error),
|
|
566
|
+
type: typeof error
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
function ensureSpanBuffer(descriptor, spanProcessor) {
|
|
570
|
+
const existing = spanProcessor.getBuffer(
|
|
571
|
+
descriptor.workflowId,
|
|
572
|
+
descriptor.runId
|
|
573
|
+
);
|
|
574
|
+
if (!existing || existing.runId !== descriptor.runId) {
|
|
575
|
+
spanProcessor.registerWorkflow(
|
|
576
|
+
descriptor.workflowId,
|
|
577
|
+
new WorkflowSpanBuffer({
|
|
578
|
+
runId: descriptor.runId,
|
|
579
|
+
taskQueue: descriptor.taskQueue,
|
|
580
|
+
workflowId: descriptor.workflowId,
|
|
581
|
+
workflowType: descriptor.workflowType
|
|
582
|
+
})
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
function normalizeSpanForGovernance(span) {
|
|
587
|
+
const attributes = asRecord(span.attributes);
|
|
588
|
+
const normalizedAttributes = {
|
|
589
|
+
...attributes
|
|
590
|
+
};
|
|
591
|
+
const urlFull = toStringOrUndefined(normalizedAttributes["url.full"]);
|
|
592
|
+
if (!toStringOrUndefined(normalizedAttributes["http.url"]) && urlFull) {
|
|
593
|
+
normalizedAttributes["http.url"] = urlFull;
|
|
594
|
+
}
|
|
595
|
+
const normalized = {
|
|
596
|
+
attributes: normalizedAttributes,
|
|
597
|
+
end_time: toFiniteNumber(span.end_time ?? span.endTime),
|
|
598
|
+
events: normalizeSpanEvents(span.events),
|
|
599
|
+
name: toStringOrUndefined(span.name),
|
|
600
|
+
span_id: toStringOrUndefined(span.span_id ?? span.spanId),
|
|
601
|
+
start_time: toFiniteNumber(span.start_time ?? span.startTime),
|
|
602
|
+
trace_id: toStringOrUndefined(span.trace_id ?? span.traceId)
|
|
603
|
+
};
|
|
604
|
+
const parentSpanId = toStringOrUndefined(
|
|
605
|
+
span.parent_span_id ?? span.parentSpanId
|
|
606
|
+
);
|
|
607
|
+
const kind = toStringOrUndefined(span.kind);
|
|
608
|
+
const durationNs = toFiniteNumber(span.duration_ns ?? span.durationNs) ?? calculateDurationNs(normalized.start_time, normalized.end_time);
|
|
609
|
+
const status = normalizeSpanStatus(span.status);
|
|
610
|
+
const requestHeaders = toStringRecord(
|
|
611
|
+
span.request_headers ?? span.requestHeaders
|
|
612
|
+
);
|
|
613
|
+
const responseHeaders = toStringRecord(
|
|
614
|
+
span.response_headers ?? span.responseHeaders
|
|
615
|
+
);
|
|
616
|
+
const requestBody = toStringOrUndefined(span.request_body ?? span.requestBody);
|
|
617
|
+
const responseBody = toStringOrUndefined(span.response_body ?? span.responseBody);
|
|
618
|
+
const semanticType = toStringOrUndefined(
|
|
619
|
+
span.semantic_type ?? span.semanticType
|
|
620
|
+
);
|
|
621
|
+
if (parentSpanId) {
|
|
622
|
+
normalized.parent_span_id = parentSpanId;
|
|
623
|
+
}
|
|
624
|
+
if (kind) {
|
|
625
|
+
normalized.kind = kind;
|
|
626
|
+
}
|
|
627
|
+
if (durationNs !== void 0) {
|
|
628
|
+
normalized.duration_ns = durationNs;
|
|
629
|
+
}
|
|
630
|
+
if (status) {
|
|
631
|
+
normalized.status = status;
|
|
632
|
+
}
|
|
633
|
+
if (requestHeaders) {
|
|
634
|
+
normalized.request_headers = requestHeaders;
|
|
635
|
+
}
|
|
636
|
+
if (responseHeaders) {
|
|
637
|
+
normalized.response_headers = responseHeaders;
|
|
638
|
+
}
|
|
639
|
+
if (requestBody !== void 0) {
|
|
640
|
+
normalized.request_body = requestBody;
|
|
641
|
+
}
|
|
642
|
+
if (responseBody !== void 0) {
|
|
643
|
+
normalized.response_body = responseBody;
|
|
644
|
+
}
|
|
645
|
+
if (semanticType) {
|
|
646
|
+
normalized.semantic_type = semanticType;
|
|
647
|
+
}
|
|
648
|
+
return normalized;
|
|
649
|
+
}
|
|
650
|
+
function calculateDurationNs(startTime, endTime) {
|
|
651
|
+
if (typeof startTime !== "number" || typeof endTime !== "number") {
|
|
652
|
+
return void 0;
|
|
653
|
+
}
|
|
654
|
+
return Math.max(0, endTime - startTime);
|
|
655
|
+
}
|
|
656
|
+
function normalizeSpanEvents(events) {
|
|
657
|
+
if (!Array.isArray(events)) {
|
|
658
|
+
return [];
|
|
659
|
+
}
|
|
660
|
+
return events.map((event) => {
|
|
661
|
+
const eventRecord = asRecord(event);
|
|
662
|
+
return {
|
|
663
|
+
attributes: asRecord(eventRecord.attributes),
|
|
664
|
+
name: toStringOrUndefined(eventRecord.name) ?? "",
|
|
665
|
+
timestamp: toFiniteNumber(eventRecord.timestamp) ?? 0
|
|
666
|
+
};
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
function normalizeSpanStatus(status) {
|
|
670
|
+
const statusRecord = asRecord(status);
|
|
671
|
+
const code = toStringOrUndefined(statusRecord.code);
|
|
672
|
+
const description = toStringOrUndefined(statusRecord.description);
|
|
673
|
+
if (!code && !description) {
|
|
674
|
+
return void 0;
|
|
675
|
+
}
|
|
676
|
+
return {
|
|
677
|
+
...code ? { code } : {},
|
|
678
|
+
...description ? { description } : {}
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
function toFiniteNumber(value) {
|
|
682
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
683
|
+
}
|
|
684
|
+
function toStringOrUndefined(value) {
|
|
685
|
+
return typeof value === "string" ? value : void 0;
|
|
686
|
+
}
|
|
687
|
+
function asRecord(value) {
|
|
688
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
689
|
+
return {};
|
|
690
|
+
}
|
|
691
|
+
return value;
|
|
692
|
+
}
|
|
693
|
+
function toStringRecord(value) {
|
|
694
|
+
const record = asRecord(value);
|
|
695
|
+
if (Object.keys(record).length === 0) {
|
|
696
|
+
return void 0;
|
|
697
|
+
}
|
|
698
|
+
const serialized = Object.fromEntries(
|
|
699
|
+
Object.entries(record).flatMap(
|
|
700
|
+
([key, entry]) => typeof entry === "string" ? [[key, entry]] : []
|
|
701
|
+
)
|
|
702
|
+
);
|
|
703
|
+
return Object.keys(serialized).length > 0 ? serialized : void 0;
|
|
704
|
+
}
|
|
705
|
+
export {
|
|
706
|
+
appendGoalToActivityInput,
|
|
707
|
+
applyRedaction,
|
|
708
|
+
executeGovernedActivity,
|
|
709
|
+
normalizeSpansForGovernance,
|
|
710
|
+
serializeValue
|
|
711
|
+
};
|
|
712
|
+
//# sourceMappingURL=activity-runtime.js.map
|