@agent-native/core 0.136.3 → 0.136.5
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/corpus/README.md +1 -1
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +53 -0
- package/corpus/templates/clips/actions/import-loom-recording.ts +7 -0
- package/corpus/templates/clips/actions/lib/loom-import-job.ts +24 -4
- package/corpus/templates/clips/changelog/2026-08-03-restart-during-a-recording-now-immediately-starts-a-fresh-ta.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +81 -30
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +436 -158
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +14 -1
- package/corpus/templates/clips/server/plugins/auth.ts +9 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +13 -0
- package/dist/client/agent-page/AgentJobsTab.js +19 -4
- package/dist/client/agent-page/use-jobs.d.ts +10 -0
- package/dist/client/agent-page/use-jobs.js +21 -0
- package/dist/client/settings/SecretsSection.js +32 -8
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/jobs/actions/run-automation-now.d.ts +6 -0
- package/dist/jobs/actions/run-automation-now.js +22 -0
- package/dist/jobs/background-automation-runner.d.ts +2 -0
- package/dist/jobs/background-automation-runner.js +22 -16
- package/dist/jobs/run-history.d.ts +17 -3
- package/dist/jobs/run-history.js +73 -7
- package/dist/jobs/run-now.d.ts +20 -0
- package/dist/jobs/run-now.js +99 -0
- package/dist/jobs/scheduler.d.ts +15 -0
- package/dist/jobs/scheduler.js +76 -12
- package/dist/localization/default-messages.d.ts +8 -0
- package/dist/localization/default-messages.js +8 -0
- package/dist/notifications/routes.d.ts +4 -4
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/secrets/routes.d.ts +5 -5
- package/dist/secrets/routes.js +41 -17
- package/dist/server/action-discovery.js +4 -0
- package/dist/server/agent-chat-plugin.js +135 -68
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/email-actions.d.ts +6 -3
- package/dist/server/email-actions.js +17 -83
- package/dist/server/email-markdown.d.ts +4 -0
- package/dist/server/email-markdown.js +174 -0
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/workspace-core/.agents/skills/automations/SKILL.md +1 -0
- package/dist/triggers/actions.d.ts +1 -1
- package/dist/triggers/actions.js +27 -5
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/automations/SKILL.md +1 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type AutomationScope } from "../automations/service.js";
|
|
2
|
+
export interface RunAutomationNowInput {
|
|
3
|
+
userEmail: string;
|
|
4
|
+
orgId?: string | null;
|
|
5
|
+
scope: AutomationScope;
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
8
|
+
export interface QueuedAutomationRun {
|
|
9
|
+
queued: true;
|
|
10
|
+
runId: string;
|
|
11
|
+
automationRunId: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function queueAutomationRunNow(input: RunAutomationNowInput): Promise<QueuedAutomationRun>;
|
|
14
|
+
/**
|
|
15
|
+
* Recover manual rows whose first serverless handoff never reached a worker.
|
|
16
|
+
* This is intentionally a redelivery, not a second execution: the worker's
|
|
17
|
+
* claim CAS decides which request owns the run.
|
|
18
|
+
*/
|
|
19
|
+
export declare function redispatchUnclaimedAutomationRuns(): Promise<number>;
|
|
20
|
+
//# sourceMappingURL=run-now.d.ts.map
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { AGENT_CHAT_BACKGROUND_RUN_FIELD, dispatchPathTargetsNetlifyBackgroundFunction, resolveAgentChatProcessRunDispatchPath, } from "../agent/durable-background.js";
|
|
2
|
+
import { canUpdateAutomationResource, } from "../automations/service.js";
|
|
3
|
+
import { isLocalDatabase } from "../db/client.js";
|
|
4
|
+
import { organizationResourceOwner, resourceGetByPath, } from "../resources/store.js";
|
|
5
|
+
import { fireInternalDispatch } from "../server/self-dispatch.js";
|
|
6
|
+
import { parseJobResource } from "./frontmatter.js";
|
|
7
|
+
import { listUnclaimedAutomationRuns, startAutomationRun, } from "./run-history.js";
|
|
8
|
+
async function dispatchAutomationRun(historyId) {
|
|
9
|
+
const dispatchPath = resolveAgentChatProcessRunDispatchPath();
|
|
10
|
+
await fireInternalDispatch({
|
|
11
|
+
path: dispatchPath,
|
|
12
|
+
taskId: historyId,
|
|
13
|
+
body: {
|
|
14
|
+
[AGENT_CHAT_BACKGROUND_RUN_FIELD]: {
|
|
15
|
+
runId: historyId,
|
|
16
|
+
automationRunId: historyId,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
...(dispatchPathTargetsNetlifyBackgroundFunction(dispatchPath)
|
|
20
|
+
? { awaitResponse: true, responseTimeoutMs: 5_000 }
|
|
21
|
+
: !isLocalDatabase()
|
|
22
|
+
? { awaitResponse: true, responseTimeoutMs: 5_000 }
|
|
23
|
+
: {}),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function ownerForScope(input) {
|
|
27
|
+
if (input.scope === "personal")
|
|
28
|
+
return input.userEmail.trim().toLowerCase();
|
|
29
|
+
if (!input.orgId) {
|
|
30
|
+
throw Object.assign(new Error("An organization is required for organization automations."), { statusCode: 400 });
|
|
31
|
+
}
|
|
32
|
+
return organizationResourceOwner(input.orgId);
|
|
33
|
+
}
|
|
34
|
+
export async function queueAutomationRunNow(input) {
|
|
35
|
+
const name = input.name.trim();
|
|
36
|
+
if (!name || name.includes("/") || name.endsWith(".md")) {
|
|
37
|
+
throw Object.assign(new Error("A valid automation name is required."), {
|
|
38
|
+
statusCode: 400,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const owner = ownerForScope(input);
|
|
42
|
+
const resource = await resourceGetByPath(owner, `jobs/${name}.md`);
|
|
43
|
+
if (!resource) {
|
|
44
|
+
throw Object.assign(new Error(`Automation "${name}" not found.`), {
|
|
45
|
+
statusCode: 404,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (!(await canUpdateAutomationResource(input, resource))) {
|
|
49
|
+
throw Object.assign(new Error("Only the automation's creator or an organization admin can run it."), { statusCode: 403 });
|
|
50
|
+
}
|
|
51
|
+
const { body } = parseJobResource(resource.content);
|
|
52
|
+
if (!body.trim()) {
|
|
53
|
+
throw Object.assign(new Error(`Automation "${name}" has no instructions.`), {
|
|
54
|
+
statusCode: 400,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// A manual-run request is a guaranteed app request even on hosts without a
|
|
58
|
+
// durable timer. Use it to recover older rows before adding the new one.
|
|
59
|
+
await redispatchUnclaimedAutomationRuns().catch((error) => {
|
|
60
|
+
console.warn("[automations] Could not sweep queued runs before run-now:", error);
|
|
61
|
+
});
|
|
62
|
+
const historyId = await startAutomationRun({
|
|
63
|
+
owner: resource.owner,
|
|
64
|
+
automation: name,
|
|
65
|
+
path: resource.path,
|
|
66
|
+
scope: input.scope,
|
|
67
|
+
orgId: input.scope === "organization" ? input.orgId : null,
|
|
68
|
+
dispatchPending: true,
|
|
69
|
+
});
|
|
70
|
+
try {
|
|
71
|
+
await dispatchAutomationRun(historyId);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
const message = error instanceof Error ? error.message : "Background dispatch failed";
|
|
75
|
+
console.warn(`[automations] Initial run-now dispatch failed; leaving ${historyId} queued for redelivery:`, message);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
return { queued: true, runId: historyId, automationRunId: historyId };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Recover manual rows whose first serverless handoff never reached a worker.
|
|
82
|
+
* This is intentionally a redelivery, not a second execution: the worker's
|
|
83
|
+
* claim CAS decides which request owns the run.
|
|
84
|
+
*/
|
|
85
|
+
export async function redispatchUnclaimedAutomationRuns() {
|
|
86
|
+
const runs = await listUnclaimedAutomationRuns();
|
|
87
|
+
let attempted = 0;
|
|
88
|
+
for (const run of runs) {
|
|
89
|
+
try {
|
|
90
|
+
await dispatchAutomationRun(run.id);
|
|
91
|
+
attempted += 1;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error(`[automations] Could not redeliver queued run ${run.id}:`, error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return attempted;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=run-now.js.map
|
package/dist/jobs/scheduler.d.ts
CHANGED
|
@@ -27,4 +27,19 @@ export interface SchedulerDeps extends BackgroundAutomationDeps {
|
|
|
27
27
|
*/
|
|
28
28
|
export declare function processRecurringJobs(deps: SchedulerDeps): Promise<void>;
|
|
29
29
|
export declare const jobRunCutOffReason: typeof backgroundRunCutOffReason;
|
|
30
|
+
interface JobExecutionResult {
|
|
31
|
+
status: "success" | "error" | "skipped";
|
|
32
|
+
runId?: string;
|
|
33
|
+
error?: string;
|
|
34
|
+
}
|
|
35
|
+
/** Execute one stored automation without changing its scheduled next run. */
|
|
36
|
+
export declare function runJobNow(owner: string, name: string, deps: SchedulerDeps, options?: {
|
|
37
|
+
historyId?: string;
|
|
38
|
+
}): Promise<JobExecutionResult>;
|
|
39
|
+
/** Process a durable run-now history row exactly once in the background worker. */
|
|
40
|
+
export declare function runQueuedAutomation(historyId: string, deps: SchedulerDeps): Promise<{
|
|
41
|
+
skipped: boolean;
|
|
42
|
+
runId?: string;
|
|
43
|
+
error?: string;
|
|
44
|
+
}>;
|
|
30
45
|
//# sourceMappingURL=scheduler.d.ts.map
|
package/dist/jobs/scheduler.js
CHANGED
|
@@ -2,6 +2,7 @@ import { resourceGetByPath, resourceListAllOwners, resourcePutIfCurrent, } from
|
|
|
2
2
|
import { backgroundRunCutOffReason, isBackgroundAutomationRunActive, resolveBackgroundAutomationIdentity, runBackgroundAutomation, } from "./background-automation-runner.js";
|
|
3
3
|
import { nextOccurrence, isValidCron, describeCron, effectiveTimezone, } from "./cron.js";
|
|
4
4
|
import { buildJobResourceContent, parseJobResource, } from "./frontmatter.js";
|
|
5
|
+
import { claimAutomationRun, finishAutomationRun, getAutomationRun, } from "./run-history.js";
|
|
5
6
|
// ─── Frontmatter parsing ────────────────────────────────────────────────────
|
|
6
7
|
export { classifyJobFrontmatter, classifyJobResource, normalizeJobMcpTools, parseJobResource, } from "./frontmatter.js";
|
|
7
8
|
export function parseJobFrontmatter(content) {
|
|
@@ -128,7 +129,7 @@ export async function processRecurringJobs(deps) {
|
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
export const jobRunCutOffReason = backgroundRunCutOffReason;
|
|
131
|
-
async function executeJob(resource, meta, body, deps, now) {
|
|
132
|
+
async function executeJob(resource, meta, body, deps, now, options = {}) {
|
|
132
133
|
const jobName = resource.path.replace(/^jobs\//, "").replace(/\.md$/, "");
|
|
133
134
|
const jobContext = {
|
|
134
135
|
name: jobName,
|
|
@@ -156,17 +157,36 @@ async function executeJob(resource, meta, body, deps, now) {
|
|
|
156
157
|
meta.lastError = identity.reason;
|
|
157
158
|
if (!alreadyRecorded)
|
|
158
159
|
await updateResource(resource, meta, body);
|
|
159
|
-
|
|
160
|
+
if (options.historyId) {
|
|
161
|
+
await finishAutomationRun(options.historyId, "error", `Automation did not run: ${identity.reason}. No delivery was confirmed.`);
|
|
162
|
+
}
|
|
163
|
+
return { status: "skipped", error: identity.reason };
|
|
160
164
|
}
|
|
161
165
|
const jobUserEmail = identity.identity.userEmail;
|
|
162
166
|
const jobOrgId = identity.identity.orgId;
|
|
167
|
+
// Manual runs use the same resource row as scheduled runs for concurrency
|
|
168
|
+
// protection. The check is paired with the conditional write below: two
|
|
169
|
+
// requests that read the same idle snapshot cannot both claim it.
|
|
170
|
+
if (options.manual && isBackgroundAutomationRunActive(meta, now)) {
|
|
171
|
+
const error = "The automation is already running.";
|
|
172
|
+
if (options.historyId) {
|
|
173
|
+
await finishAutomationRun(options.historyId, "error", `${error} No delivery was confirmed.`);
|
|
174
|
+
}
|
|
175
|
+
return { status: "skipped", error };
|
|
176
|
+
}
|
|
163
177
|
// Mark as running
|
|
164
178
|
meta.lastRun = now.toISOString();
|
|
165
179
|
meta.lastStatus = "running";
|
|
166
180
|
meta.lastError = undefined;
|
|
167
181
|
if (!(await updateResource(resource, meta, body))) {
|
|
168
182
|
console.log(`[recurring-jobs] "${resource.path}" changed before it could start; dropping this tick.`);
|
|
169
|
-
|
|
183
|
+
if (options.historyId) {
|
|
184
|
+
await finishAutomationRun(options.historyId, "error", "The automation changed before the run could start. No delivery was confirmed.");
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
status: "error",
|
|
188
|
+
error: "The automation changed before the run could start.",
|
|
189
|
+
};
|
|
170
190
|
}
|
|
171
191
|
const requestContext = meta.originScopeId && meta.deliveryPlatform && meta.deliveryDestination
|
|
172
192
|
? {
|
|
@@ -193,33 +213,74 @@ async function executeJob(resource, meta, body, deps, now) {
|
|
|
193
213
|
}
|
|
194
214
|
: undefined;
|
|
195
215
|
try {
|
|
196
|
-
await runBackgroundAutomation({
|
|
216
|
+
const result = await runBackgroundAutomation({
|
|
197
217
|
automation: jobContext,
|
|
198
218
|
ownerEmail: jobUserEmail,
|
|
199
219
|
orgId: jobOrgId,
|
|
200
|
-
prompt:
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
220
|
+
prompt: options.manual
|
|
221
|
+
? `[Manual Automation Run: ${jobName}]\nThis run was explicitly started by the automation owner. Execute the following instructions now:\n\n${body}`
|
|
222
|
+
: `[Recurring Job: ${jobName}]\nSchedule: ${describeCron(meta.schedule, effectiveTimezone(meta.timezone))}\n\nExecute the following job instructions:\n\n${body}`,
|
|
223
|
+
threadTitle: `${options.manual ? "Automation" : "Job"}: ${jobName} — ${now.toLocaleDateString()}`,
|
|
224
|
+
runIdPrefix: `${options.manual ? "manual" : "job"}-${jobName}`,
|
|
225
|
+
usageLabel: `${options.manual ? "manual-automation" : "recurring-job"}:${jobName}`,
|
|
204
226
|
requestContext,
|
|
227
|
+
...(options.historyId ? { historyId: options.historyId } : {}),
|
|
228
|
+
actionCaller: "automation",
|
|
205
229
|
}, deps);
|
|
206
230
|
await recordExecutionOutcome(resource, {
|
|
207
231
|
lastRun: meta.lastRun,
|
|
208
232
|
lastStatus: "success",
|
|
209
233
|
lastError: undefined,
|
|
234
|
+
advanceSchedule: options.advanceSchedule,
|
|
210
235
|
});
|
|
211
236
|
console.log(`[recurring-jobs] Job "${jobName}" completed.`);
|
|
237
|
+
return { status: "success", runId: result.runId };
|
|
212
238
|
}
|
|
213
239
|
catch (err) {
|
|
214
240
|
const lastError = err instanceof Error ? err.message.slice(0, 200) : "Unknown error";
|
|
241
|
+
const reportedError = `${lastError}. No delivery was confirmed.`;
|
|
215
242
|
await recordExecutionOutcome(resource, {
|
|
216
243
|
lastRun: meta.lastRun,
|
|
217
244
|
lastStatus: "error",
|
|
218
|
-
lastError,
|
|
245
|
+
lastError: reportedError,
|
|
246
|
+
advanceSchedule: options.advanceSchedule,
|
|
219
247
|
});
|
|
220
|
-
console.error(`[recurring-jobs] Job "${jobName}" failed:`,
|
|
248
|
+
console.error(`[recurring-jobs] Job "${jobName}" failed:`, reportedError);
|
|
249
|
+
return { status: "error", error: reportedError };
|
|
221
250
|
}
|
|
222
251
|
}
|
|
252
|
+
/** Execute one stored automation without changing its scheduled next run. */
|
|
253
|
+
export async function runJobNow(owner, name, deps, options = {}) {
|
|
254
|
+
const path = `jobs/${name}.md`;
|
|
255
|
+
const resource = await resourceGetByPath(owner, path);
|
|
256
|
+
if (!resource)
|
|
257
|
+
throw new Error(`Automation "${name}" not found.`);
|
|
258
|
+
const { meta, body } = parseJobFrontmatter(resource.content);
|
|
259
|
+
if (!body.trim())
|
|
260
|
+
throw new Error(`Automation "${name}" has no instructions.`);
|
|
261
|
+
return executeJob(resource, meta, body, deps, new Date(), {
|
|
262
|
+
advanceSchedule: false,
|
|
263
|
+
historyId: options.historyId,
|
|
264
|
+
manual: true,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/** Process a durable run-now history row exactly once in the background worker. */
|
|
268
|
+
export async function runQueuedAutomation(historyId, deps) {
|
|
269
|
+
const queued = await getAutomationRun(historyId);
|
|
270
|
+
if (!queued)
|
|
271
|
+
throw new Error(`Automation run "${historyId}" not found.`);
|
|
272
|
+
if (!(await claimAutomationRun(historyId))) {
|
|
273
|
+
return { skipped: true };
|
|
274
|
+
}
|
|
275
|
+
const result = await runJobNow(queued.owner, queued.automation, deps, {
|
|
276
|
+
historyId,
|
|
277
|
+
});
|
|
278
|
+
return {
|
|
279
|
+
skipped: false,
|
|
280
|
+
...(result.runId ? { runId: result.runId } : {}),
|
|
281
|
+
...(result.error ? { error: result.error } : {}),
|
|
282
|
+
};
|
|
283
|
+
}
|
|
223
284
|
async function updateResource(resource, meta, body) {
|
|
224
285
|
const content = buildJobContent(meta, body);
|
|
225
286
|
const written = await resourcePutIfCurrent({
|
|
@@ -256,8 +317,11 @@ async function recordExecutionOutcome(resource, outcome) {
|
|
|
256
317
|
return;
|
|
257
318
|
}
|
|
258
319
|
const current = parseJobResource(latest.content);
|
|
259
|
-
const
|
|
260
|
-
|
|
320
|
+
const { advanceSchedule, ...execution } = outcome;
|
|
321
|
+
const meta = { ...current.meta, ...execution };
|
|
322
|
+
if (advanceSchedule !== false &&
|
|
323
|
+
meta.schedule &&
|
|
324
|
+
isValidCron(meta.schedule)) {
|
|
261
325
|
// Measured from completion so a long run cannot immediately re-fire.
|
|
262
326
|
meta.nextRun = nextOccurrence(meta.schedule, new Date(), meta.timezone).toISOString();
|
|
263
327
|
}
|
|
@@ -57,6 +57,11 @@ declare const messages: {
|
|
|
57
57
|
scopeLabel: string;
|
|
58
58
|
scopePersonal: string;
|
|
59
59
|
scopeWorkspace: string;
|
|
60
|
+
testStoredValue: string;
|
|
61
|
+
candidateValueWorking: string;
|
|
62
|
+
storedValueWorking: string;
|
|
63
|
+
invalid: string;
|
|
64
|
+
testFailed: string;
|
|
60
65
|
scopePersonalDescription: string;
|
|
61
66
|
scopeWorkspaceDescription: string;
|
|
62
67
|
};
|
|
@@ -562,6 +567,9 @@ declare const messages: {
|
|
|
562
567
|
eventTrigger: string;
|
|
563
568
|
deleteAutomationTitle: string;
|
|
564
569
|
deleteAutomationDescription: string;
|
|
570
|
+
runNow: string;
|
|
571
|
+
runNowTitle: string;
|
|
572
|
+
runNowDescription: string;
|
|
565
573
|
automationDetails: string;
|
|
566
574
|
automationEventDetails: string;
|
|
567
575
|
condition: string;
|
|
@@ -62,6 +62,11 @@ const messages = {
|
|
|
62
62
|
scopeLabel: "Scope",
|
|
63
63
|
scopePersonal: "Personal",
|
|
64
64
|
scopeWorkspace: "Workspace",
|
|
65
|
+
testStoredValue: "Test",
|
|
66
|
+
candidateValueWorking: "New value works",
|
|
67
|
+
storedValueWorking: "Working",
|
|
68
|
+
invalid: "Invalid",
|
|
69
|
+
testFailed: "Test failed",
|
|
65
70
|
scopePersonalDescription: "Only your own signed-in sessions use this key. Integration, webhook, scheduled job, automation, and agent-to-agent runs sign in as their owner rather than as you, so they cannot read it.",
|
|
66
71
|
scopeWorkspaceDescription: "Everyone in this workspace uses this key, including integration, webhook, scheduled job, automation, and agent-to-agent runs.",
|
|
67
72
|
},
|
|
@@ -567,6 +572,9 @@ const messages = {
|
|
|
567
572
|
eventTrigger: "Event-triggered",
|
|
568
573
|
deleteAutomationTitle: "Delete automation?",
|
|
569
574
|
deleteAutomationDescription: "This permanently removes the automation and cannot be undone.",
|
|
575
|
+
runNow: "Run now",
|
|
576
|
+
runNowTitle: "Run automation now?",
|
|
577
|
+
runNowDescription: "This runs the automation's real actions immediately. It may send messages or change data, and it will not change the next scheduled run.",
|
|
570
578
|
automationDetails: "Automation details",
|
|
571
579
|
automationEventDetails: "Runs when {{event}}.",
|
|
572
580
|
condition: "Condition",
|
|
@@ -16,19 +16,19 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
|
|
|
16
16
|
error?: undefined;
|
|
17
17
|
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
|
-
count?: undefined;
|
|
20
19
|
updated: number;
|
|
21
20
|
error?: undefined;
|
|
22
21
|
ok?: undefined;
|
|
23
|
-
} | {
|
|
24
22
|
count?: undefined;
|
|
23
|
+
} | {
|
|
25
24
|
updated?: undefined;
|
|
26
25
|
error: string;
|
|
27
26
|
ok?: undefined;
|
|
28
|
-
} | {
|
|
29
27
|
count?: undefined;
|
|
28
|
+
} | {
|
|
30
29
|
updated?: undefined;
|
|
31
|
-
error?: undefined;
|
|
32
30
|
ok: boolean;
|
|
31
|
+
error?: undefined;
|
|
32
|
+
count?: undefined;
|
|
33
33
|
}>>;
|
|
34
34
|
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
41
41
|
thumbsUpRate: number;
|
|
42
42
|
avgEvalScore: number;
|
|
43
43
|
} | {
|
|
44
|
-
error?: undefined;
|
|
45
44
|
summary: import("./types.js").TraceSummary;
|
|
46
45
|
spans: import("./types.js").TraceSpan[];
|
|
47
46
|
id?: undefined;
|
|
47
|
+
error?: undefined;
|
|
48
48
|
ok?: undefined;
|
|
49
49
|
} | {
|
|
50
|
-
error?: undefined;
|
|
51
50
|
summary?: undefined;
|
|
52
51
|
spans?: undefined;
|
|
53
52
|
id: string;
|
|
53
|
+
error?: undefined;
|
|
54
54
|
ok?: undefined;
|
|
55
55
|
} | {
|
|
56
56
|
summary?: undefined;
|
|
@@ -59,10 +59,10 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
59
59
|
error: any;
|
|
60
60
|
ok?: undefined;
|
|
61
61
|
} | {
|
|
62
|
-
error?: undefined;
|
|
63
62
|
summary?: undefined;
|
|
64
63
|
spans?: undefined;
|
|
65
64
|
id?: undefined;
|
|
66
65
|
ok: boolean;
|
|
66
|
+
error?: undefined;
|
|
67
67
|
}>>;
|
|
68
68
|
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -75,10 +75,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
-
message?: undefined;
|
|
79
|
-
id?: undefined;
|
|
80
|
-
found?: undefined;
|
|
81
78
|
deleted?: undefined;
|
|
79
|
+
found?: undefined;
|
|
82
80
|
providers: {
|
|
83
81
|
id: string;
|
|
84
82
|
label: string;
|
|
@@ -91,42 +89,44 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
91
89
|
count: number;
|
|
92
90
|
provider?: undefined;
|
|
93
91
|
registered?: undefined;
|
|
92
|
+
id?: undefined;
|
|
94
93
|
label?: undefined;
|
|
95
|
-
} | {
|
|
96
94
|
message?: undefined;
|
|
97
|
-
|
|
95
|
+
} | {
|
|
98
96
|
deleted?: undefined;
|
|
99
|
-
providers?: undefined;
|
|
100
97
|
count?: undefined;
|
|
98
|
+
providers?: undefined;
|
|
101
99
|
found: boolean;
|
|
102
100
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
103
101
|
registered?: undefined;
|
|
102
|
+
id?: undefined;
|
|
104
103
|
label?: undefined;
|
|
105
|
-
} | {
|
|
106
104
|
message?: undefined;
|
|
105
|
+
} | {
|
|
107
106
|
deleted?: undefined;
|
|
108
|
-
providers?: undefined;
|
|
109
107
|
count?: undefined;
|
|
108
|
+
providers?: undefined;
|
|
110
109
|
provider?: undefined;
|
|
111
110
|
found: boolean;
|
|
112
111
|
id: string;
|
|
113
112
|
registered?: undefined;
|
|
114
113
|
label?: undefined;
|
|
115
|
-
} | {
|
|
116
114
|
message?: undefined;
|
|
115
|
+
} | {
|
|
116
|
+
count?: undefined;
|
|
117
117
|
found?: undefined;
|
|
118
118
|
providers?: undefined;
|
|
119
|
-
count?: undefined;
|
|
120
119
|
provider?: undefined;
|
|
121
120
|
deleted: boolean;
|
|
122
121
|
id: string;
|
|
123
122
|
registered?: undefined;
|
|
124
123
|
label?: undefined;
|
|
124
|
+
message?: undefined;
|
|
125
125
|
} | {
|
|
126
|
-
found?: undefined;
|
|
127
126
|
deleted?: undefined;
|
|
128
|
-
providers?: undefined;
|
|
129
127
|
count?: undefined;
|
|
128
|
+
found?: undefined;
|
|
129
|
+
providers?: undefined;
|
|
130
130
|
provider?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|
|
@@ -329,9 +329,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
329
329
|
label?: undefined;
|
|
330
330
|
message?: undefined;
|
|
331
331
|
} | {
|
|
332
|
-
count?: undefined;
|
|
333
332
|
id?: undefined;
|
|
334
333
|
deleted?: undefined;
|
|
334
|
+
count?: undefined;
|
|
335
335
|
providers?: undefined;
|
|
336
336
|
found: boolean;
|
|
337
337
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
@@ -339,9 +339,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
339
339
|
label?: undefined;
|
|
340
340
|
message?: undefined;
|
|
341
341
|
} | {
|
|
342
|
-
count?: undefined;
|
|
343
342
|
provider?: undefined;
|
|
344
343
|
deleted?: undefined;
|
|
344
|
+
count?: undefined;
|
|
345
345
|
providers?: undefined;
|
|
346
346
|
found: boolean;
|
|
347
347
|
id: string;
|
|
@@ -349,9 +349,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
349
349
|
label?: undefined;
|
|
350
350
|
message?: undefined;
|
|
351
351
|
} | {
|
|
352
|
-
count?: undefined;
|
|
353
352
|
provider?: undefined;
|
|
354
353
|
found?: undefined;
|
|
354
|
+
count?: undefined;
|
|
355
355
|
providers?: undefined;
|
|
356
356
|
deleted: boolean;
|
|
357
357
|
id: string;
|
|
@@ -359,10 +359,10 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
359
359
|
label?: undefined;
|
|
360
360
|
message?: undefined;
|
|
361
361
|
} | {
|
|
362
|
-
count?: undefined;
|
|
363
362
|
provider?: undefined;
|
|
364
363
|
deleted?: undefined;
|
|
365
364
|
found?: undefined;
|
|
365
|
+
count?: undefined;
|
|
366
366
|
providers?: undefined;
|
|
367
367
|
registered: boolean;
|
|
368
368
|
id: string;
|
|
@@ -73,6 +73,7 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
73
73
|
offset?: unknown;
|
|
74
74
|
limit?: unknown;
|
|
75
75
|
}, {
|
|
76
|
+
deleted?: undefined;
|
|
76
77
|
jobs: {
|
|
77
78
|
id: string;
|
|
78
79
|
name: string;
|
|
@@ -83,7 +84,6 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
83
84
|
updatedAt: string;
|
|
84
85
|
}[];
|
|
85
86
|
total: number;
|
|
86
|
-
deleted?: undefined;
|
|
87
87
|
jobId?: undefined;
|
|
88
88
|
} | {
|
|
89
89
|
jobs?: undefined;
|
|
@@ -91,9 +91,9 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
91
91
|
deleted: boolean;
|
|
92
92
|
jobId: string;
|
|
93
93
|
} | {
|
|
94
|
+
deleted?: undefined;
|
|
94
95
|
jobs?: undefined;
|
|
95
96
|
total?: undefined;
|
|
96
|
-
deleted?: undefined;
|
|
97
97
|
jobId?: undefined;
|
|
98
98
|
hits: Record<string, unknown>[];
|
|
99
99
|
offset: number;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -34,29 +34,29 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
|
|
|
34
34
|
/** POST /_agent-native/secrets/:key — write a secret. */
|
|
35
35
|
export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
36
36
|
error: string;
|
|
37
|
-
status?: undefined;
|
|
38
37
|
ok?: undefined;
|
|
38
|
+
status?: undefined;
|
|
39
39
|
} | {
|
|
40
40
|
error?: undefined;
|
|
41
41
|
ok: boolean;
|
|
42
42
|
status: string;
|
|
43
43
|
} | {
|
|
44
|
+
ok?: undefined;
|
|
44
45
|
error: string;
|
|
45
46
|
removed?: undefined;
|
|
46
|
-
ok?: undefined;
|
|
47
47
|
} | {
|
|
48
48
|
error?: undefined;
|
|
49
49
|
ok: boolean;
|
|
50
50
|
removed: boolean;
|
|
51
51
|
}>>;
|
|
52
52
|
/**
|
|
53
|
-
* POST /_agent-native/secrets/:key/test —
|
|
54
|
-
* current stored value without changing anything.
|
|
53
|
+
* POST /_agent-native/secrets/:key/test — validate an optional candidate value
|
|
54
|
+
* or the current stored value without changing anything.
|
|
55
55
|
*/
|
|
56
56
|
export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
57
|
+
ok?: undefined;
|
|
57
58
|
error: string;
|
|
58
59
|
note?: undefined;
|
|
59
|
-
ok?: undefined;
|
|
60
60
|
} | {
|
|
61
61
|
error?: undefined;
|
|
62
62
|
ok: boolean;
|
package/dist/secrets/routes.js
CHANGED
|
@@ -277,8 +277,8 @@ async function handleDelete(event, secret) {
|
|
|
277
277
|
return { ok: true, removed };
|
|
278
278
|
}
|
|
279
279
|
/**
|
|
280
|
-
* POST /_agent-native/secrets/:key/test —
|
|
281
|
-
* current stored value without changing anything.
|
|
280
|
+
* POST /_agent-native/secrets/:key/test — validate an optional candidate value
|
|
281
|
+
* or the current stored value without changing anything.
|
|
282
282
|
*/
|
|
283
283
|
export function createTestSecretHandler() {
|
|
284
284
|
return defineEventHandler(async (event) => {
|
|
@@ -301,25 +301,49 @@ export function createTestSecretHandler() {
|
|
|
301
301
|
const has = await hasOAuthSecretForEvent(event, secret).catch(() => false);
|
|
302
302
|
return { ok: has };
|
|
303
303
|
}
|
|
304
|
-
|
|
305
|
-
|
|
304
|
+
const body = (await readBody(event).catch(() => ({})));
|
|
305
|
+
const hasCandidateValue = Object.hasOwn(body, "value");
|
|
306
|
+
const candidateValue = typeof body.value === "string" ? body.value.trim() : undefined;
|
|
307
|
+
if (hasCandidateValue && !candidateValue) {
|
|
308
|
+
setResponseStatus(event, 400);
|
|
309
|
+
return { error: "value must be a non-empty string" };
|
|
306
310
|
}
|
|
307
|
-
const { scopeId } = await resolveScopeId(event, secret.scope);
|
|
311
|
+
const { scopeId, reason } = await resolveScopeId(event, secret.scope);
|
|
308
312
|
if (!scopeId) {
|
|
309
313
|
setResponseStatus(event, 401);
|
|
310
|
-
return { error: "Unable to resolve scope" };
|
|
314
|
+
return { error: reason ?? "Unable to resolve scope" };
|
|
311
315
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
316
|
+
if (secret.scope === "workspace" &&
|
|
317
|
+
!(await canMutateWorkspaceScope(event, scopeId))) {
|
|
318
|
+
setResponseStatus(event, 403);
|
|
319
|
+
return {
|
|
320
|
+
error: "Only organization owners and admins can set workspace-scoped secrets",
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
if (secret.scope === "org" && !(await canMutateOrgScope(event, scopeId))) {
|
|
324
|
+
setResponseStatus(event, 403);
|
|
325
|
+
return {
|
|
326
|
+
error: "Only organization owners and admins can set org-scoped secrets",
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
if (!secret.validator) {
|
|
330
|
+
return { ok: true, note: "No validator registered" };
|
|
331
|
+
}
|
|
332
|
+
let value = candidateValue;
|
|
333
|
+
if (!value) {
|
|
334
|
+
const stored = await readAppSecret({
|
|
335
|
+
key: secret.key,
|
|
336
|
+
scope: secret.scope,
|
|
337
|
+
scopeId,
|
|
338
|
+
});
|
|
339
|
+
if (!stored) {
|
|
340
|
+
setResponseStatus(event, 404);
|
|
341
|
+
return { error: "No value stored" };
|
|
342
|
+
}
|
|
343
|
+
value = stored.value;
|
|
320
344
|
}
|
|
321
345
|
try {
|
|
322
|
-
const result = await secret.validator(
|
|
346
|
+
const result = await secret.validator(value);
|
|
323
347
|
const ok = typeof result === "boolean" ? result : result?.ok === true;
|
|
324
348
|
if (!ok) {
|
|
325
349
|
const err = typeof result === "object" && result && result.error
|
|
@@ -327,7 +351,7 @@ export function createTestSecretHandler() {
|
|
|
327
351
|
: "Validator rejected the value";
|
|
328
352
|
return {
|
|
329
353
|
ok: false,
|
|
330
|
-
error: redactSecretFromMessage(err,
|
|
354
|
+
error: redactSecretFromMessage(err, value),
|
|
331
355
|
};
|
|
332
356
|
}
|
|
333
357
|
return { ok: true };
|
|
@@ -338,7 +362,7 @@ export function createTestSecretHandler() {
|
|
|
338
362
|
: "Validator threw";
|
|
339
363
|
return {
|
|
340
364
|
ok: false,
|
|
341
|
-
error: redactSecretFromMessage(message,
|
|
365
|
+
error: redactSecretFromMessage(message, value),
|
|
342
366
|
};
|
|
343
367
|
}
|
|
344
368
|
});
|
|
@@ -540,6 +540,10 @@ export async function mergeCoreSharingActions(registry) {
|
|
|
540
540
|
"manage-recurring-job",
|
|
541
541
|
() => import("../jobs/actions/manage-recurring-job.js"),
|
|
542
542
|
],
|
|
543
|
+
[
|
|
544
|
+
"run-automation-now",
|
|
545
|
+
() => import("../jobs/actions/run-automation-now.js"),
|
|
546
|
+
],
|
|
543
547
|
[
|
|
544
548
|
"list-automation-runs",
|
|
545
549
|
() => import("../jobs/actions/list-automation-runs.js"),
|