@agent-native/core 0.204.0 → 0.204.1-nightly-20261008034100
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/action.js +5 -6
- package/dist/agent/auto-continue.d.ts +35 -0
- package/dist/agent/auto-continue.js +38 -0
- package/dist/agent/connection-required-note.d.ts +52 -0
- package/dist/agent/connection-required-note.js +187 -0
- package/dist/agent/jev-tool-prefetch.d.ts +5 -1
- package/dist/agent/jev-tool-prefetch.js +19 -6
- package/dist/agent/previous-turn-note.d.ts +9 -0
- package/dist/agent/previous-turn-note.js +48 -0
- package/dist/agent/production-agent.d.ts +17 -13
- package/dist/agent/production-agent.js +185 -43
- package/dist/agent/reaped-run-thread.d.ts +13 -0
- package/dist/agent/reaped-run-thread.js +45 -0
- package/dist/agent/run-store.d.ts +29 -5
- package/dist/agent/run-store.js +144 -30
- package/dist/agent/thread-data-builder.d.ts +16 -0
- package/dist/agent/thread-data-builder.js +30 -8
- package/dist/agent/thread-message-projection.js +5 -3
- package/dist/agent/tool-search.js +5 -1
- package/dist/agent/types.d.ts +3 -0
- package/dist/audit/config.d.ts +6 -0
- package/dist/audit/config.js +12 -1
- package/dist/audit/index.d.ts +1 -1
- package/dist/audit/index.js +1 -1
- package/dist/audit/store.js +39 -4
- package/dist/cli/skills.d.ts +1 -0
- package/dist/cli/skills.js +1 -1
- package/dist/client/chat/agentkit-agent-native.js +83 -7
- package/dist/client/chat/agentkit-protocol.js +140 -67
- package/dist/client/chat/runtime.js +5 -3
- package/dist/client/use-run-stuck-detection.d.ts +18 -1
- package/dist/client/use-run-stuck-detection.js +115 -75
- package/dist/db/request-telemetry.d.ts +7 -1
- package/dist/db/request-telemetry.js +20 -1
- package/dist/deploy/build.d.ts +25 -1
- package/dist/deploy/build.js +176 -3
- package/dist/deploy/workspace-deploy.js +8 -3
- package/dist/extensions/fetch-tool.js +50 -14
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/integrations/adapters/email.js +11 -3
- package/dist/integrations/adapters/telegram.js +4 -2
- package/dist/jobs/actions/automation-no-op.d.ts +12 -0
- package/dist/jobs/actions/automation-no-op.js +20 -0
- package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
- package/dist/jobs/background-automation-runner.d.ts +8 -1
- package/dist/jobs/background-automation-runner.js +102 -19
- package/dist/jobs/run-history.d.ts +1 -1
- package/dist/jobs/run-history.js +8 -4
- package/dist/jobs/scheduler.js +25 -12
- package/dist/localization/automation-outcome-messages.d.ts +22 -0
- package/dist/localization/automation-outcome-messages.js +90 -0
- package/dist/localization/default-messages.d.ts +2 -0
- package/dist/localization/default-messages.js +4 -2
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/metrics.d.ts +3 -0
- package/dist/observability/metrics.js +10 -0
- package/dist/observability/migrations.js +22 -0
- package/dist/observability/routes.d.ts +13 -8
- package/dist/observability/routes.js +88 -14
- package/dist/observability/sentiment.d.ts +5 -0
- package/dist/observability/sentiment.js +75 -25
- package/dist/observability/store.d.ts +28 -0
- package/dist/observability/store.js +58 -0
- package/dist/observability/traces.js +37 -5
- package/dist/org/index.d.ts +2 -2
- package/dist/progress/actions.js +1 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.js +6 -2
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.d.ts +1 -0
- package/dist/provider-api/index.js +18 -0
- package/dist/provider-api/result-outcome.d.ts +1 -0
- package/dist/provider-api/result-outcome.js +20 -0
- package/dist/provider-api/staging.js +10 -9
- package/dist/server/agent-chat/prompt-resources.d.ts +8 -2
- package/dist/server/agent-chat/prompt-resources.js +30 -7
- package/dist/server/agent-chat/recurring-jobs-runtime.d.ts +19 -4
- package/dist/server/agent-chat/recurring-jobs-runtime.js +52 -16
- package/dist/server/agent-chat/sweep-trigger-auth.d.ts +18 -0
- package/dist/server/agent-chat/sweep-trigger-auth.js +36 -0
- package/dist/server/agent-chat-plugin.js +20 -13
- package/dist/server/agent-engine-default-model-route.d.ts +2 -2
- package/dist/server/auth.js +4 -4
- package/dist/server/framework-request-handler.js +19 -0
- package/dist/server/http-response-telemetry.js +4 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/request-context.d.ts +6 -0
- package/dist/shared/context-status.d.ts +21 -0
- package/dist/shared/context-status.js +54 -0
- package/dist/templates/chat/app/components/chat/ChatRouteContent.tsx +8 -1
- package/dist/templates/workspace-core/.agents/skills/automations/SKILL.md +8 -1
- package/dist/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +3 -1
- package/dist/triggers/actions/manage-automation.d.ts +7 -7
- package/dist/triggers/dispatcher.js +10 -7
- package/docs/content/audit-log.mdx +3 -3
- package/docs/content/cloudflare.mdx +27 -0
- package/docs/content/deployment-environment-variables.mdx +2 -0
- package/docs/content/durable-resume.mdx +3 -1
- package/docs/content/environment-variables.mdx +2 -0
- package/docs/content/recurring-jobs.mdx +29 -9
- package/docs/content/vercel.mdx +30 -0
- package/package.json +3 -3
- package/src/templates/chat/app/components/chat/ChatRouteContent.tsx +8 -1
- package/src/templates/workspace-core/.agents/skills/automations/SKILL.md +8 -1
- package/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +3 -1
|
@@ -660,6 +660,64 @@ export async function getTraceSummary(runId, opts = {}) {
|
|
|
660
660
|
return null;
|
|
661
661
|
return rowToTraceSummary(rows[0]);
|
|
662
662
|
}
|
|
663
|
+
/**
|
|
664
|
+
* A thread created on a path with no request org keeps `org_id` NULL, and every
|
|
665
|
+
* review read requires `thread.org_id` to equal the trace's org, so its runs
|
|
666
|
+
* never reach Human Review. The run that executed under an org is the proof of
|
|
667
|
+
* which org the thread belongs to: adopt it, for the thread's own owner only
|
|
668
|
+
* and only while `org_id` is NULL.
|
|
669
|
+
*
|
|
670
|
+
* A private thread's `org_id` grants nothing but that review access (owner
|
|
671
|
+
* access ignores it, shares do not read it, and `visibility = 'org'` is the only
|
|
672
|
+
* way it scopes sharing), while `thread_data` holds every run's conversation. So
|
|
673
|
+
* a private thread whose owner's runs span more than one org belongs to none of
|
|
674
|
+
* them: the second statement unassigns it. Org-visible threads keep their
|
|
675
|
+
* `org_id`, which is an explicit sharing scope.
|
|
676
|
+
*
|
|
677
|
+
* Both statements run after this run's own summary is committed
|
|
678
|
+
* (`upsertTraceSummary` is awaited first), so of two concurrent runs under
|
|
679
|
+
* different orgs the one whose statements run later always sees the other's
|
|
680
|
+
* committed org. If this run's adopt raced ahead of the other run's summary, the
|
|
681
|
+
* other run's unassign undoes it, or, when that ran before this adopt
|
|
682
|
+
* committed, this run's own unassign does, since it starts after the adopt.
|
|
683
|
+
* No lock is needed.
|
|
684
|
+
*
|
|
685
|
+
* The multi-org signal is derived from `agent_trace_summaries`, so it is only
|
|
686
|
+
* as durable as those rows: retention purges them, and a run that never wrote a
|
|
687
|
+
* summary is invisible to it. A thread unassigned for spanning orgs can
|
|
688
|
+
* therefore be re-adopted once the other org's summaries age out.
|
|
689
|
+
*/
|
|
690
|
+
export async function adoptTraceOrgForThread(summary) {
|
|
691
|
+
if (!summary.orgId || !summary.threadId || !summary.userId)
|
|
692
|
+
return;
|
|
693
|
+
const client = getDbExec();
|
|
694
|
+
// The subqueries only run for a thread owned by the caller (the other
|
|
695
|
+
// predicates short-circuit first) and probe
|
|
696
|
+
// idx_trace_summaries_thread_user_created by thread_id.
|
|
697
|
+
await client.execute({
|
|
698
|
+
sql: `UPDATE chat_threads SET org_id = ?
|
|
699
|
+
WHERE id = ? AND org_id IS NULL AND LOWER(owner_email) = LOWER(?)
|
|
700
|
+
AND NOT EXISTS (
|
|
701
|
+
SELECT 1 FROM agent_trace_summaries other
|
|
702
|
+
WHERE other.thread_id = chat_threads.id
|
|
703
|
+
AND LOWER(other.user_id) = LOWER(chat_threads.owner_email)
|
|
704
|
+
AND other.org_id IS NOT NULL AND other.org_id <> ?
|
|
705
|
+
)`,
|
|
706
|
+
args: [summary.orgId, summary.threadId, summary.userId, summary.orgId],
|
|
707
|
+
});
|
|
708
|
+
await client.execute({
|
|
709
|
+
sql: `UPDATE chat_threads SET org_id = NULL
|
|
710
|
+
WHERE id = ? AND org_id IS NOT NULL AND visibility = 'private'
|
|
711
|
+
AND LOWER(owner_email) = LOWER(?)
|
|
712
|
+
AND EXISTS (
|
|
713
|
+
SELECT 1 FROM agent_trace_summaries other
|
|
714
|
+
WHERE other.thread_id = chat_threads.id
|
|
715
|
+
AND LOWER(other.user_id) = LOWER(chat_threads.owner_email)
|
|
716
|
+
AND other.org_id IS NOT NULL AND other.org_id <> chat_threads.org_id
|
|
717
|
+
)`,
|
|
718
|
+
args: [summary.threadId, summary.userId],
|
|
719
|
+
});
|
|
720
|
+
}
|
|
663
721
|
export async function getOrgScopedThreadData(orgId, ownerEmail, threadIds) {
|
|
664
722
|
const ids = [...new Set(threadIds.filter(Boolean))];
|
|
665
723
|
if (!orgId || !ownerEmail || ids.length === 0)
|
|
@@ -6,7 +6,7 @@ import { MAX_AI_CONTENT_BYTES, MAX_AI_SPANS_PER_RUN, boundAiContent, emitAiSpanE
|
|
|
6
6
|
import { sanitizeToolErrorMessage, TOOL_ERROR_DETAIL_METADATA_KEY, toolErrorSignature, } from "./trace-error.js";
|
|
7
7
|
import { redactCapturedString, redactSensitiveFields, } from "./trace-redaction.js";
|
|
8
8
|
export { redactSensitiveFields } from "./trace-redaction.js";
|
|
9
|
-
import { recordAgentToolCall, recordGenAiChat } from "./metrics.js";
|
|
9
|
+
import { recordAgentToolCall, recordGenAiChat, recordTraceWriteFailure, } from "./metrics.js";
|
|
10
10
|
import { endAgentSpan, startAgentSpan, withAgentSpanContext, } from "./tracing.js";
|
|
11
11
|
import { trackingIdentityProperties } from "./tracking-identity.js";
|
|
12
12
|
function spanId() {
|
|
@@ -1328,7 +1328,7 @@ export async function instrumentAgentLoop(opts) {
|
|
|
1328
1328
|
model: usage?.model ?? loopOpts.model,
|
|
1329
1329
|
createdAt: runStart,
|
|
1330
1330
|
};
|
|
1331
|
-
writeTraceData(spans, summary, runId, config).catch(() =>
|
|
1331
|
+
writeTraceData(spans, summary, runId, config).catch((error) => reportTraceWriteFailure(runId, "write", error));
|
|
1332
1332
|
try {
|
|
1333
1333
|
// Metrics are unsampled and independent of trace export.
|
|
1334
1334
|
for (const [tripIndex, trip] of modelRoundTrips.entries()) {
|
|
@@ -1463,6 +1463,7 @@ export async function instrumentAgentLoop(opts) {
|
|
|
1463
1463
|
if (precedingResponse) {
|
|
1464
1464
|
const { inferAndTrackSentiment } = await import("./sentiment.js");
|
|
1465
1465
|
await inferAndTrackSentiment({
|
|
1466
|
+
runEngine: loopOpts.engine,
|
|
1466
1467
|
classifierModel: config.inferredSentimentModel,
|
|
1467
1468
|
precedingResponseModel: precedingResponse.model,
|
|
1468
1469
|
text: opts.sentimentInput,
|
|
@@ -1480,10 +1481,41 @@ export async function instrumentAgentLoop(opts) {
|
|
|
1480
1481
|
}
|
|
1481
1482
|
return usage;
|
|
1482
1483
|
}
|
|
1484
|
+
/**
|
|
1485
|
+
* A trace that fails to persist leaves the run unreviewable and makes a
|
|
1486
|
+
* thumbs-down for it unlinkable, so it is reported once per run and stage,
|
|
1487
|
+
* never silently and never per span.
|
|
1488
|
+
*/
|
|
1489
|
+
function reportTraceWriteFailure(runId, stage, error, detail = {}) {
|
|
1490
|
+
recordTraceWriteFailure(stage, error);
|
|
1491
|
+
console.warn(`[agent-native] observability: could not persist trace ${stage} for run ${runId}`, {
|
|
1492
|
+
...detail,
|
|
1493
|
+
error: toolErrorSignature(error instanceof Error ? error.message : String(error)),
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1483
1496
|
async function writeTraceData(spans, summary, runId, config) {
|
|
1484
|
-
const { insertTraceSpan, upsertTraceSummary } = await import("./store.js");
|
|
1485
|
-
|
|
1486
|
-
|
|
1497
|
+
const { adoptTraceOrgForThread, insertTraceSpan, upsertTraceSummary } = await import("./store.js");
|
|
1498
|
+
let spanFailures = 0;
|
|
1499
|
+
let firstSpanError;
|
|
1500
|
+
await Promise.all(spans.map((span) => insertTraceSpan({ ...span, orgId: summary.orgId ?? null }).catch((error) => {
|
|
1501
|
+
spanFailures += 1;
|
|
1502
|
+
firstSpanError ??= error;
|
|
1503
|
+
})));
|
|
1504
|
+
if (spanFailures > 0) {
|
|
1505
|
+
reportTraceWriteFailure(runId, "spans", firstSpanError, {
|
|
1506
|
+
failed: spanFailures,
|
|
1507
|
+
total: spans.length,
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
// Adoption reads other runs' summaries to detect a thread spanning orgs, so
|
|
1511
|
+
// it is only sound once this run's own org is on record too.
|
|
1512
|
+
const summaryWritten = await upsertTraceSummary(summary).then(() => true, (error) => {
|
|
1513
|
+
reportTraceWriteFailure(runId, "summary", error);
|
|
1514
|
+
return false;
|
|
1515
|
+
});
|
|
1516
|
+
if (summaryWritten) {
|
|
1517
|
+
await adoptTraceOrgForThread(summary).catch((error) => reportTraceWriteFailure(runId, "thread_org", error));
|
|
1518
|
+
}
|
|
1487
1519
|
try {
|
|
1488
1520
|
const { evaluateRun } = await import("./evals.js");
|
|
1489
1521
|
await evaluateRun(runId, { sampleRate: config.evalSampleRate });
|
package/dist/org/index.d.ts
CHANGED
|
@@ -177,10 +177,10 @@ export declare const getMyOrgHandler: import("h3").EventHandlerWithFetch<import(
|
|
|
177
177
|
soloDeploymentAdmin: boolean | undefined;
|
|
178
178
|
}>>;
|
|
179
179
|
export declare const createOrgHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
180
|
+
success: boolean;
|
|
181
|
+
name?: undefined;
|
|
180
182
|
role?: undefined;
|
|
181
183
|
id?: undefined;
|
|
182
|
-
name?: undefined;
|
|
183
|
-
success: boolean;
|
|
184
184
|
} | {
|
|
185
185
|
success?: undefined;
|
|
186
186
|
id: string;
|
package/dist/progress/actions.js
CHANGED
|
@@ -15,6 +15,7 @@ function parseLimit(value, fallback = 20) {
|
|
|
15
15
|
export function createProgressToolEntries(getCurrentUser) {
|
|
16
16
|
return {
|
|
17
17
|
"manage-progress": {
|
|
18
|
+
confirmsAutomationWork: false,
|
|
18
19
|
tool: {
|
|
19
20
|
description: `Track multi-step task progress visible to the user in the runs tray.
|
|
20
21
|
|
|
@@ -75,9 +75,10 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
-
deleted?: undefined;
|
|
79
78
|
message?: undefined;
|
|
80
|
-
|
|
79
|
+
deleted?: undefined;
|
|
80
|
+
id?: undefined;
|
|
81
|
+
provider?: undefined;
|
|
81
82
|
providers: {
|
|
82
83
|
id: string;
|
|
83
84
|
label: string;
|
|
@@ -88,46 +89,45 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
88
89
|
updatedAt: number;
|
|
89
90
|
}[];
|
|
90
91
|
count: number;
|
|
91
|
-
|
|
92
|
+
found?: undefined;
|
|
92
93
|
registered?: undefined;
|
|
93
|
-
id?: undefined;
|
|
94
94
|
label?: undefined;
|
|
95
95
|
} | {
|
|
96
|
-
deleted?: undefined;
|
|
97
96
|
message?: undefined;
|
|
97
|
+
deleted?: undefined;
|
|
98
|
+
id?: undefined;
|
|
98
99
|
providers?: undefined;
|
|
99
100
|
count?: undefined;
|
|
100
101
|
found: boolean;
|
|
101
102
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
102
103
|
registered?: undefined;
|
|
103
|
-
id?: undefined;
|
|
104
104
|
label?: undefined;
|
|
105
105
|
} | {
|
|
106
|
-
deleted?: undefined;
|
|
107
106
|
message?: undefined;
|
|
107
|
+
deleted?: undefined;
|
|
108
|
+
provider?: undefined;
|
|
108
109
|
providers?: undefined;
|
|
109
110
|
count?: undefined;
|
|
110
|
-
provider?: undefined;
|
|
111
111
|
found: boolean;
|
|
112
112
|
id: string;
|
|
113
113
|
registered?: undefined;
|
|
114
114
|
label?: undefined;
|
|
115
115
|
} | {
|
|
116
116
|
message?: undefined;
|
|
117
|
-
|
|
117
|
+
provider?: undefined;
|
|
118
118
|
providers?: undefined;
|
|
119
119
|
count?: undefined;
|
|
120
|
-
|
|
120
|
+
found?: undefined;
|
|
121
121
|
deleted: boolean;
|
|
122
122
|
id: string;
|
|
123
123
|
registered?: undefined;
|
|
124
124
|
label?: undefined;
|
|
125
125
|
} | {
|
|
126
126
|
deleted?: undefined;
|
|
127
|
-
|
|
127
|
+
provider?: undefined;
|
|
128
128
|
providers?: undefined;
|
|
129
129
|
count?: undefined;
|
|
130
|
-
|
|
130
|
+
found?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|
|
133
133
|
label: string;
|
|
@@ -313,9 +313,7 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
313
313
|
}, {
|
|
314
314
|
id?: undefined;
|
|
315
315
|
deleted?: undefined;
|
|
316
|
-
provider?: undefined;
|
|
317
316
|
message?: undefined;
|
|
318
|
-
found?: undefined;
|
|
319
317
|
providers: {
|
|
320
318
|
id: string;
|
|
321
319
|
label: string;
|
|
@@ -326,6 +324,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
326
324
|
updatedAt: number;
|
|
327
325
|
}[];
|
|
328
326
|
count: number;
|
|
327
|
+
provider?: undefined;
|
|
328
|
+
found?: undefined;
|
|
329
329
|
registered?: undefined;
|
|
330
330
|
label?: undefined;
|
|
331
331
|
} | {
|
|
@@ -340,30 +340,30 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
340
340
|
label?: undefined;
|
|
341
341
|
} | {
|
|
342
342
|
deleted?: undefined;
|
|
343
|
-
provider?: undefined;
|
|
344
343
|
message?: undefined;
|
|
345
344
|
providers?: undefined;
|
|
346
345
|
count?: undefined;
|
|
346
|
+
provider?: undefined;
|
|
347
347
|
found: boolean;
|
|
348
348
|
id: string;
|
|
349
349
|
registered?: undefined;
|
|
350
350
|
label?: undefined;
|
|
351
351
|
} | {
|
|
352
|
-
provider?: undefined;
|
|
353
352
|
message?: undefined;
|
|
354
|
-
found?: undefined;
|
|
355
353
|
providers?: undefined;
|
|
356
354
|
count?: undefined;
|
|
355
|
+
provider?: undefined;
|
|
356
|
+
found?: undefined;
|
|
357
357
|
deleted: boolean;
|
|
358
358
|
id: string;
|
|
359
359
|
registered?: undefined;
|
|
360
360
|
label?: undefined;
|
|
361
361
|
} | {
|
|
362
362
|
deleted?: undefined;
|
|
363
|
-
provider?: undefined;
|
|
364
|
-
found?: undefined;
|
|
365
363
|
providers?: undefined;
|
|
366
364
|
count?: undefined;
|
|
365
|
+
provider?: undefined;
|
|
366
|
+
found?: undefined;
|
|
367
367
|
registered: boolean;
|
|
368
368
|
id: string;
|
|
369
369
|
label: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineAction, } from "../../action.js";
|
|
3
3
|
import { getCredentialContext } from "../../server/request-context.js";
|
|
4
|
+
import { rejectFailedProviderResult } from "../result-outcome.js";
|
|
4
5
|
import { stagingExecuteRequest } from "../staging.js";
|
|
5
6
|
import { createCustomProviderRegistrationAction, } from "./custom-provider-registration.js";
|
|
6
7
|
import { buildProviderApiAuditSummary } from "./provider-api-audit.js";
|
|
@@ -261,7 +262,7 @@ export function createProviderApiRequestAction(runtime, options = {}) {
|
|
|
261
262
|
rethrowStagingError(error);
|
|
262
263
|
}
|
|
263
264
|
}
|
|
264
|
-
return runtime.executeRequest(args);
|
|
265
|
+
return rejectFailedProviderResult(args.provider, await runtime.executeRequest(args));
|
|
265
266
|
},
|
|
266
267
|
});
|
|
267
268
|
}
|
|
@@ -291,7 +292,10 @@ export function createProviderApiDocsAction(runtime, options = {}) {
|
|
|
291
292
|
schema,
|
|
292
293
|
http: options.http ?? { method: "GET" },
|
|
293
294
|
readOnly: true,
|
|
294
|
-
run: async (rawArgs) =>
|
|
295
|
+
run: async (rawArgs) => {
|
|
296
|
+
const args = rawArgs;
|
|
297
|
+
return rejectFailedProviderResult(args.provider, await runtime.fetchDocs(args));
|
|
298
|
+
},
|
|
295
299
|
});
|
|
296
300
|
}
|
|
297
301
|
export function createProviderApiActions(runtime, options = {}) {
|
|
@@ -73,7 +73,6 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
73
73
|
offset?: unknown;
|
|
74
74
|
limit?: unknown;
|
|
75
75
|
}, {
|
|
76
|
-
deleted?: undefined;
|
|
77
76
|
jobs: {
|
|
78
77
|
id: string;
|
|
79
78
|
name: string;
|
|
@@ -84,6 +83,7 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
84
83
|
updatedAt: string;
|
|
85
84
|
}[];
|
|
86
85
|
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;
|
|
95
94
|
jobs?: undefined;
|
|
96
95
|
total?: undefined;
|
|
96
|
+
deleted?: undefined;
|
|
97
97
|
jobId?: undefined;
|
|
98
98
|
hits: Record<string, unknown>[];
|
|
99
99
|
offset: number;
|
|
@@ -513,3 +513,4 @@ export declare function readGitHubRepositoryFile(args: GitHubRepositoryFileReadA
|
|
|
513
513
|
export declare function writeGitHubRepositoryFile(args: GitHubRepositoryFileWriteArgs, runtime: ProviderApiRuntimeOptions): Promise<GitHubRepositoryFileWriteResult>;
|
|
514
514
|
export declare function deleteGitHubRepositoryFile(args: GitHubRepositoryFileDeleteArgs, runtime: ProviderApiRuntimeOptions): Promise<GitHubRepositoryFileDeleteResult>;
|
|
515
515
|
export declare function defaultProviderApiCredentialResolver(options: ProviderApiCredentialLookupOptions): Promise<ProviderApiResolvedCredential | null>;
|
|
516
|
+
export declare function providerApiResponseOutcomeForUrl(url: string, response: Pick<ProviderApiHttpResponse, "ok" | "statusText">, body: string): Pick<ProviderApiHttpResponse, "ok" | "statusText">;
|
|
@@ -3950,6 +3950,24 @@ function providerQuotaExhaustedResponse(detail) {
|
|
|
3950
3950
|
},
|
|
3951
3951
|
};
|
|
3952
3952
|
}
|
|
3953
|
+
export function providerApiResponseOutcomeForUrl(url, response, body) {
|
|
3954
|
+
const target = new URL(url);
|
|
3955
|
+
const config = Object.values(PROVIDER_CONFIGS).find((candidate) => {
|
|
3956
|
+
if (!candidate.bodyOkField)
|
|
3957
|
+
return false;
|
|
3958
|
+
const base = new URL(candidate.defaultBaseUrl);
|
|
3959
|
+
const path = base.pathname.replace(/\/$/, "");
|
|
3960
|
+
return (target.origin === base.origin &&
|
|
3961
|
+
(target.pathname === path || target.pathname.startsWith(`${path}/`)));
|
|
3962
|
+
});
|
|
3963
|
+
return config
|
|
3964
|
+
? applyBodyEnvelopeOutcome({
|
|
3965
|
+
ok: response.ok,
|
|
3966
|
+
statusText: response.statusText,
|
|
3967
|
+
json: tryParseJson(body),
|
|
3968
|
+
}, config)
|
|
3969
|
+
: response;
|
|
3970
|
+
}
|
|
3953
3971
|
function applyBodyEnvelopeOutcome(response, config) {
|
|
3954
3972
|
const field = config.bodyOkField;
|
|
3955
3973
|
if (!field || !response.ok)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function rejectFailedProviderResult<T>(provider: string, result: T): T;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { fail } from "../action.js";
|
|
2
|
+
export function rejectFailedProviderResult(provider, result) {
|
|
3
|
+
if (!result || typeof result !== "object")
|
|
4
|
+
return result;
|
|
5
|
+
const record = result;
|
|
6
|
+
const response = record.response && typeof record.response === "object"
|
|
7
|
+
? record.response
|
|
8
|
+
: record;
|
|
9
|
+
if (response.ok !== false)
|
|
10
|
+
return result;
|
|
11
|
+
const status = response.status;
|
|
12
|
+
fail(`${provider}: HTTP ${status} ${response.statusText ?? ""}\n\n${JSON.stringify(response.json ?? response.text ?? response).slice(0, 2000)}`, {
|
|
13
|
+
statusCode: typeof status === "number" && status >= 400 && status <= 599
|
|
14
|
+
? status
|
|
15
|
+
: 400,
|
|
16
|
+
errorCode: typeof status === "number" && status >= 400
|
|
17
|
+
? `http_${status}`
|
|
18
|
+
: "provider_api_rejected",
|
|
19
|
+
});
|
|
20
|
+
}
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
* secret redaction are fully preserved. We read the raw (pre-redacted) JSON
|
|
24
24
|
* here; redaction is applied to the response returned to the model.
|
|
25
25
|
*/
|
|
26
|
+
import { fail } from "../action.js";
|
|
27
|
+
import { rejectFailedProviderResult } from "./result-outcome.js";
|
|
26
28
|
import { upsertStagedDataset, deriveColumns, MAX_ROWS_PER_APP, } from "./staged-datasets-store.js";
|
|
27
29
|
function getAtPath(obj, path) {
|
|
28
30
|
if (!path || obj === undefined || obj === null)
|
|
@@ -174,18 +176,21 @@ export async function stagingExecuteRequest(args, execute, ctx) {
|
|
|
174
176
|
const retryAt = typeof json?.retryAt === "string"
|
|
175
177
|
? ` Retry after ${json.retryAt}.`
|
|
176
178
|
: "";
|
|
177
|
-
|
|
179
|
+
fail(`Provider API quota exhausted (429).${retryAt}`, {
|
|
180
|
+
statusCode: 429,
|
|
181
|
+
errorCode: "http_429",
|
|
182
|
+
});
|
|
178
183
|
}
|
|
179
184
|
if (attempt >= 5) {
|
|
180
|
-
|
|
181
|
-
`Try again later or reduce the page count
|
|
185
|
+
fail(`Provider returned 429 Too Many Requests after ${attempt + 1} attempts. ` +
|
|
186
|
+
`Try again later or reduce the page count.`, { statusCode: 429, errorCode: "http_429" });
|
|
182
187
|
}
|
|
183
188
|
const waitMs = getRetryAfterMs(response.headers, attempt);
|
|
184
189
|
await sleepMs(waitMs);
|
|
185
190
|
attempt++;
|
|
186
191
|
continue;
|
|
187
192
|
}
|
|
188
|
-
result = raw;
|
|
193
|
+
result = rejectFailedProviderResult(args.provider, raw);
|
|
189
194
|
break;
|
|
190
195
|
}
|
|
191
196
|
pages++;
|
|
@@ -195,11 +200,7 @@ export async function stagingExecuteRequest(args, execute, ctx) {
|
|
|
195
200
|
}
|
|
196
201
|
const response = result.response;
|
|
197
202
|
if (!response?.ok) {
|
|
198
|
-
|
|
199
|
-
throw new Error(`Provider API returned status ${response?.status}: ${JSON.stringify(response?.json ?? response?.text).slice(0, 200)}`);
|
|
200
|
-
}
|
|
201
|
-
truncated = true;
|
|
202
|
-
break;
|
|
203
|
+
fail(`Provider API returned status ${response?.status}: ${JSON.stringify(response?.json ?? response?.text).slice(0, 200)}`, { errorCode: "provider_api_rejected" });
|
|
203
204
|
}
|
|
204
205
|
const body = response.json ??
|
|
205
206
|
(response.text ? tryParseJson(response.text) : null);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type JevCandidate } from "../../agent/jev-tool-prefetch.js";
|
|
2
2
|
import { type FrameworkToolGroup } from "../../framework-tools.js";
|
|
3
|
+
import type { ContextStatus } from "../../shared/context-status.js";
|
|
3
4
|
import type { ContextGovernanceTier, ContextManifestSourceRef, ContextSystemProvenance } from "../../shared/context-xray.js";
|
|
4
5
|
import type { BuilderGatewayAuth } from "../credential-provider.js";
|
|
5
6
|
export declare const COMPACT_PROMPT_RESOURCE_MAX_CHARS = 6000;
|
|
@@ -72,7 +73,12 @@ export interface PromptSectionBudgetResult {
|
|
|
72
73
|
}
|
|
73
74
|
export declare function selectPromptSectionsWithinBudget(sections: PromptSection[], maxChars: number): PromptSectionBudgetResult;
|
|
74
75
|
export declare function resourceScopeForOwner(owner: string, currentOwner?: string): string;
|
|
75
|
-
export
|
|
76
|
+
export interface JevPreloadResult {
|
|
77
|
+
context: string;
|
|
78
|
+
status: ContextStatus;
|
|
79
|
+
}
|
|
80
|
+
export declare function preloadJevContextForPrompt(options: Parameters<typeof preloadJevContextWithStatus>[0]): Promise<string>;
|
|
81
|
+
export declare function preloadJevContextWithStatus(options: {
|
|
76
82
|
request: string;
|
|
77
83
|
appId?: string;
|
|
78
84
|
owner?: string;
|
|
@@ -87,7 +93,7 @@ export declare function preloadJevContextForPrompt(options: {
|
|
|
87
93
|
contextPrefetchDeadlineAt?: number;
|
|
88
94
|
dispatchToBackground?: boolean;
|
|
89
95
|
internalContinuation?: boolean;
|
|
90
|
-
}): Promise<
|
|
96
|
+
}): Promise<JevPreloadResult>;
|
|
91
97
|
/**
|
|
92
98
|
* Pre-load the agent's context: AGENTS.md (workspace/template/runtime
|
|
93
99
|
* instructions), the skills index, shared LEARNINGS.md (team notes), a shared
|
|
@@ -866,16 +866,26 @@ function recordAnalyticsPreloadedReferenceCount(input) {
|
|
|
866
866
|
};
|
|
867
867
|
}
|
|
868
868
|
export async function preloadJevContextForPrompt(options) {
|
|
869
|
+
return (await preloadJevContextWithStatus(options)).context;
|
|
870
|
+
}
|
|
871
|
+
export async function preloadJevContextWithStatus(options) {
|
|
869
872
|
const request = options.request.trim();
|
|
870
873
|
const apiKey = options.apiKey?.trim();
|
|
871
874
|
const personalApiKey = options.personalApiKey?.trim();
|
|
872
875
|
if (!request || options.maxChars === 0 || options.dispatchToBackground) {
|
|
873
|
-
return "";
|
|
876
|
+
return { context: "", status: "empty" };
|
|
874
877
|
}
|
|
875
878
|
const deadlineAt = options.contextPrefetchDeadlineAt ?? Date.now() + JEV_PRELOAD_BUDGET_MS;
|
|
876
879
|
const hasJev = Boolean(apiKey || personalApiKey || options.builderAuth);
|
|
877
880
|
let runtimeCandidates = [];
|
|
878
881
|
let memoryContext = { candidates: [], fallbackIds: [] };
|
|
882
|
+
// A stage that timed out or threw only matters when nothing was injected: an
|
|
883
|
+
// empty result is then a loss, not an answer, and the model has to be told.
|
|
884
|
+
let degraded;
|
|
885
|
+
const finish = (context, injected) => ({
|
|
886
|
+
context,
|
|
887
|
+
status: injected > 0 ? "ok" : (degraded ?? "empty"),
|
|
888
|
+
});
|
|
879
889
|
try {
|
|
880
890
|
const collection = await withinPromptBudget((signal) => Promise.all([
|
|
881
891
|
hasJev
|
|
@@ -895,10 +905,12 @@ export async function preloadJevContextForPrompt(options) {
|
|
|
895
905
|
memoryContext = collection.value[1];
|
|
896
906
|
}
|
|
897
907
|
else {
|
|
908
|
+
degraded = "timed_out";
|
|
898
909
|
console.warn("[agent] Prompt context candidates exceeded the preload budget; keeping Analytics retrieval fallback.");
|
|
899
910
|
}
|
|
900
911
|
}
|
|
901
912
|
catch (error) {
|
|
913
|
+
degraded = "failed";
|
|
902
914
|
console.warn("[agent] Prompt context candidates unavailable; keeping Analytics retrieval fallback.", error instanceof Error ? error.message : "unknown error");
|
|
903
915
|
}
|
|
904
916
|
const candidates = [
|
|
@@ -915,7 +927,7 @@ export async function preloadJevContextForPrompt(options) {
|
|
|
915
927
|
candidates,
|
|
916
928
|
selectedIds: [],
|
|
917
929
|
});
|
|
918
|
-
return "";
|
|
930
|
+
return finish("", 0);
|
|
919
931
|
}
|
|
920
932
|
const categoryFor = (candidate) => {
|
|
921
933
|
const kind = candidate.metadata?.kind ?? candidate.kind;
|
|
@@ -971,13 +983,24 @@ export async function preloadJevContextForPrompt(options) {
|
|
|
971
983
|
}
|
|
972
984
|
}
|
|
973
985
|
else {
|
|
986
|
+
degraded ??= "timed_out";
|
|
974
987
|
console.warn("[agent] Jev ranking exceeded the preload budget; using bounded retrieval fallbacks.");
|
|
975
988
|
}
|
|
976
989
|
}
|
|
977
990
|
catch (error) {
|
|
991
|
+
degraded ??= "failed";
|
|
978
992
|
console.warn("[agent] Jev ranking unavailable; using bounded retrieval fallbacks.", error instanceof Error ? error.message : "unknown error");
|
|
979
993
|
}
|
|
980
994
|
}
|
|
995
|
+
// A ranking that was attempted and lost is a degraded turn, not an empty
|
|
996
|
+
// answer; the fallbacks below still run for it.
|
|
997
|
+
for (const result of rankings.values()) {
|
|
998
|
+
if (result.status === "failed")
|
|
999
|
+
degraded = "failed";
|
|
1000
|
+
else if (result.status === "timed_out")
|
|
1001
|
+
degraded ??= "timed_out";
|
|
1002
|
+
}
|
|
1003
|
+
const isRanked = (result) => result?.status === "selected" || result?.status === "no-match";
|
|
981
1004
|
const jevSelectedIds = [...rankings.values()]
|
|
982
1005
|
.filter((result) => result.status === "selected")
|
|
983
1006
|
.flatMap((result) => result.ids);
|
|
@@ -1002,13 +1025,13 @@ export async function preloadJevContextForPrompt(options) {
|
|
|
1002
1025
|
for (const id of highSimilarityReferenceIds)
|
|
1003
1026
|
selected.add(id);
|
|
1004
1027
|
}
|
|
1005
|
-
else if (!referenceRanking
|
|
1028
|
+
else if (!isRanked(referenceRanking)) {
|
|
1006
1029
|
for (const id of options.fallbackCandidateIds ?? [])
|
|
1007
1030
|
selected.add(id);
|
|
1008
1031
|
}
|
|
1009
1032
|
}
|
|
1010
1033
|
const memoryRanking = rankings.get("memory");
|
|
1011
|
-
if ((!hasJev || !memoryRanking
|
|
1034
|
+
if ((!hasJev || !isRanked(memoryRanking)) &&
|
|
1012
1035
|
memoryContext.fallbackIds.length > 0) {
|
|
1013
1036
|
for (const id of memoryContext.fallbackIds)
|
|
1014
1037
|
selected.add(id);
|
|
@@ -1061,7 +1084,7 @@ export async function preloadJevContextForPrompt(options) {
|
|
|
1061
1084
|
candidates,
|
|
1062
1085
|
injectedIds: new Set(),
|
|
1063
1086
|
});
|
|
1064
|
-
return "";
|
|
1087
|
+
return finish("", 0);
|
|
1065
1088
|
}
|
|
1066
1089
|
const maxItemChars = options.compact ? 6_000 : JEV_CONTEXT_ITEM_MAX_CHARS;
|
|
1067
1090
|
const maxTotalChars = Math.min(options.compact ? 16_000 : JEV_CONTEXT_TOTAL_MAX_CHARS, Math.max(0, options.maxChars ?? Number.POSITIVE_INFINITY));
|
|
@@ -1109,8 +1132,8 @@ export async function preloadJevContextForPrompt(options) {
|
|
|
1109
1132
|
injectedIds,
|
|
1110
1133
|
});
|
|
1111
1134
|
if (blocks.length === 0)
|
|
1112
|
-
return "";
|
|
1113
|
-
return `${JEV_CONTEXT_PREFIX}${escapeJevContextFence(blocks.join(JEV_CONTEXT_SEPARATOR))}${JEV_CONTEXT_SUFFIX}
|
|
1135
|
+
return finish("", 0);
|
|
1136
|
+
return finish(`${JEV_CONTEXT_PREFIX}${escapeJevContextFence(blocks.join(JEV_CONTEXT_SEPARATOR))}${JEV_CONTEXT_SUFFIX}`, blocks.length);
|
|
1114
1137
|
}
|
|
1115
1138
|
/**
|
|
1116
1139
|
* Pre-load the agent's context: AGENTS.md (workspace/template/runtime
|
|
@@ -1,16 +1,31 @@
|
|
|
1
|
-
type RecurringJobsRuntimeEnvKey = "AGENT_NATIVE_BUILD_RECURRING_JOBS" | "AGENT_NATIVE_DISABLE_RECURRING_JOBS" | "AGENT_NATIVE_ENABLE_LOCAL_RECURRING_JOBS" | "APP_URL" | "BETTER_AUTH_URL" | "CF_PAGES" | "DEPLOY_URL" | "AWS_EXECUTION_ENV" | "AWS_LAMBDA_FUNCTION_NAME" | "NETLIFY" | "NETLIFY_LOCAL" | "NITRO_PRESET" | "NODE_ENV" | "SITE_ID" | "URL" | "VERCEL" | "VITE_APP_URL" | "VITE_WORKSPACE_GATEWAY_URL" | "WORKSPACE_GATEWAY_URL";
|
|
1
|
+
type RecurringJobsRuntimeEnvKey = "A2A_SECRET" | "AGENT_NATIVE_BUILD_RECURRING_JOBS" | "AGENT_NATIVE_DISABLE_RECURRING_JOBS" | "AGENT_NATIVE_ENABLE_LOCAL_RECURRING_JOBS" | "APP_URL" | "BETTER_AUTH_URL" | "CF_PAGES" | "CRON_SECRET" | "DEPLOY_URL" | "AWS_EXECUTION_ENV" | "AWS_LAMBDA_FUNCTION_NAME" | "NETLIFY" | "NETLIFY_LOCAL" | "NITRO_PRESET" | "NODE_ENV" | "SITE_ID" | "URL" | "VERCEL" | "VERCEL_ENV" | "VITE_APP_URL" | "VITE_WORKSPACE_GATEWAY_URL" | "WORKSPACE_GATEWAY_URL";
|
|
2
2
|
type RecurringJobsRuntimeEnv = Partial<Record<RecurringJobsRuntimeEnvKey, string | undefined>>;
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Runtime facts the environment cannot carry. A Cloudflare Worker exposes its
|
|
5
|
+
* bindings only on the request, so the generated worker entry marks the
|
|
6
|
+
* isolate instead of setting an env var.
|
|
7
|
+
*/
|
|
8
|
+
export interface RecurringJobsPlatform {
|
|
9
|
+
cloudflareWorker: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function shouldDisableRecurringJobsRuntime(env?: RecurringJobsRuntimeEnv, platform?: RecurringJobsPlatform): boolean;
|
|
4
12
|
export declare function isNetlifyRecurringJobsRuntime(env?: RecurringJobsRuntimeEnv): boolean;
|
|
5
13
|
export type RecurringJobsBuildMarker = "enabled" | "disabled";
|
|
6
14
|
export declare const RECURRING_JOBS_BUILD_MARKER_ENV_VAR = "AGENT_NATIVE_BUILD_RECURRING_JOBS";
|
|
7
15
|
export declare function resolveRecurringJobsBuildMarker(env?: RecurringJobsRuntimeEnv): RecurringJobsBuildMarker;
|
|
16
|
+
export type PlatformScheduledTriggerDriver = "netlify-scheduled-function" | "vercel-cron" | "cloudflare-cron-trigger";
|
|
17
|
+
export type ScheduledTriggerDriver = PlatformScheduledTriggerDriver | "in-process";
|
|
8
18
|
export type ScheduledTriggerAvailability = {
|
|
9
19
|
available: true;
|
|
10
|
-
driver:
|
|
20
|
+
driver: ScheduledTriggerDriver;
|
|
11
21
|
} | {
|
|
12
22
|
available: false;
|
|
13
23
|
reason: "disabled-by-env" | "no-platform-scheduler" | "local-development";
|
|
24
|
+
} | {
|
|
25
|
+
available: false;
|
|
26
|
+
reason: "missing-trigger-secret";
|
|
27
|
+
driver: PlatformScheduledTriggerDriver;
|
|
28
|
+
secret: "CRON_SECRET" | "A2A_SECRET";
|
|
14
29
|
};
|
|
15
|
-
export declare function scheduledTriggerAvailability(env?: RecurringJobsRuntimeEnv): ScheduledTriggerAvailability;
|
|
30
|
+
export declare function scheduledTriggerAvailability(env?: RecurringJobsRuntimeEnv, platform?: RecurringJobsPlatform): ScheduledTriggerAvailability;
|
|
16
31
|
export {};
|