@agent-native/core 0.214.0 → 0.217.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/dist/action.js +54 -1
- package/dist/agent/actions/disconnect-chatgpt-subscription.js +5 -0
- package/dist/agent/actions/get-agentkit-capabilities.js +3 -3
- package/dist/agent/actions/manage-builder-connection.js +5 -0
- package/dist/agent/actions/manage-provider-key-policy.js +5 -0
- package/dist/agent/actions/manage-provider-models.js +5 -0
- package/dist/agent/actions/manage-service-providers.js +5 -0
- package/dist/agent/actions/select-chatgpt-subscription-account.js +5 -0
- package/dist/agent/context-xray/actions/context-evict.js +5 -0
- package/dist/agent/context-xray/actions/context-pin.js +5 -0
- package/dist/agent/context-xray/actions/context-report.js +5 -0
- package/dist/agent/context-xray/actions/context-restore.js +5 -0
- package/dist/agent/execution-fence.d.ts +1 -0
- package/dist/agent/execution-fence.js +5 -0
- package/dist/agent/production-agent.d.ts +35 -2
- package/dist/agent/production-agent.js +629 -32
- package/dist/agent/run-manager.d.ts +2 -0
- package/dist/agent/run-manager.js +397 -115
- package/dist/agent/run-slot-lock.d.ts +2 -0
- package/dist/agent/run-slot-lock.js +6 -0
- package/dist/agent/run-store.d.ts +5 -0
- package/dist/agent/run-store.js +423 -156
- package/dist/agent/thread-data-builder.js +27 -5
- package/dist/agent/types.d.ts +6 -12
- package/dist/agentkit/capabilities.d.ts +1 -1
- package/dist/app-config/analytics.js +1 -1
- package/dist/application-state/store.d.ts +5 -0
- package/dist/application-state/store.js +26 -0
- package/dist/automation/index.d.ts +1 -1
- package/dist/chat-threads/schema-migrations.js +17 -0
- package/dist/chat-threads/store.d.ts +21 -1
- package/dist/chat-threads/store.js +223 -41
- package/dist/cli/skills-content/turn-into-app-skill.d.ts +1 -1
- package/dist/cli/skills-content/turn-into-app-skill.js +20 -18
- package/dist/cli/templates-meta.js +14 -0
- package/dist/client/analytics-session.d.ts +7 -0
- package/dist/client/analytics-session.js +27 -1
- package/dist/client/analytics.js +276 -31
- package/dist/client/chat/agentkit-agent-native.js +79 -3
- package/dist/client/chat/agentkit-protocol.js +80 -42
- package/dist/client/chat/runtime.d.ts +5 -1
- package/dist/client/chat/runtime.js +46 -3
- package/dist/client/consent.d.ts +48 -0
- package/dist/client/consent.js +413 -0
- package/dist/client/onboarding/index.d.ts +1 -0
- package/dist/client/onboarding/index.js +1 -0
- package/dist/client/onboarding/use-onboarding-checklist.d.ts +23 -0
- package/dist/client/onboarding/use-onboarding-checklist.js +115 -0
- package/dist/client/review/use-review.d.ts +2 -0
- package/dist/client/review/use-review.js +28 -1
- package/dist/client/session-replay.d.ts +1 -1
- package/dist/client/session-replay.js +142 -3
- package/dist/client/sharing/useResourceAccessGate.d.ts +3 -2
- package/dist/client/sharing/useResourceAccessGate.js +9 -1
- package/dist/client/use-chat-thread-list.d.ts +2 -0
- package/dist/client/use-chat-thread-list.js +12 -2
- package/dist/client/use-chat-threads.d.ts +1 -0
- package/dist/client/use-chat-threads.js +2 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/connections/catalog.d.ts +5 -5
- package/dist/connections/catalog.js +22 -3
- package/dist/data-widgets/index.d.ts +36 -2
- package/dist/data-widgets/index.js +94 -6
- package/dist/db/migrations.js +4 -1
- package/dist/db/schema-snapshot.generated.js +8 -1
- package/dist/feature-flags/actions/set-feature-flag.js +5 -0
- package/dist/feature-flags/index.d.ts +1 -1
- package/dist/feature-flags/index.js +1 -1
- package/dist/feature-flags/store.d.ts +12 -0
- package/dist/feature-flags/store.js +79 -7
- package/dist/file-upload/actions/manage-file-storage.js +5 -0
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.js +5 -0
- package/dist/history/actions/create-resource-version.js +5 -0
- package/dist/history/actions/restore-resource-version.js +5 -0
- package/dist/ingestion/index.d.ts +1 -1
- package/dist/ingestion/index.js +1 -1
- package/dist/ingestion/pptx.d.ts +11 -0
- package/dist/ingestion/pptx.js +81 -1
- package/dist/integrations/actions/manage-messaging-channel.js +5 -0
- package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
- package/dist/jobs/scheduler.js +17 -1
- package/dist/labs/actions/set-lab.js +5 -0
- package/dist/localization/actions/set-localization-preference.js +5 -0
- package/dist/localization/consent-banner-messages.d.ts +16 -0
- package/dist/localization/consent-banner-messages.js +149 -0
- package/dist/localization/core-messages.js +4 -0
- package/dist/localization/default-messages.d.ts +1 -0
- package/dist/localization/default-messages.js +2 -0
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/actions/save-observability-instruction-update.js +5 -0
- package/dist/observability/actions/save-observability-review-summary.js +5 -0
- package/dist/observability/routes.d.ts +6 -6
- package/dist/onboarding/index.d.ts +2 -1
- package/dist/onboarding/index.js +1 -0
- package/dist/onboarding/plugin.js +55 -46
- package/dist/onboarding/status.d.ts +15 -0
- package/dist/onboarding/status.js +59 -0
- package/dist/onboarding/types.d.ts +12 -0
- package/dist/onboarding/types.js +2 -1
- package/dist/org/workspace-app-access.js +19 -9
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.js +9 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/review/actions/consume-review-feedback.js +5 -0
- package/dist/review/actions/create-review-comment.js +5 -0
- package/dist/review/actions/delete-review-comment.js +5 -0
- package/dist/review/actions/react-to-review-comment.js +5 -0
- package/dist/review/actions/reply-review-comment.js +5 -0
- package/dist/review/actions/resolve-review-thread.js +5 -0
- package/dist/review/actions/send-review-thread-to-agent.js +5 -0
- package/dist/review/actions/set-review-status.js +5 -0
- package/dist/review/actions/set-review-thread-muted.js +5 -0
- package/dist/review/actions/set-review-thread-unread.js +5 -0
- package/dist/review/actions/set-review-threads-unread.js +5 -0
- package/dist/review/actions/update-review-comment-anchor.js +5 -0
- package/dist/review/actions/update-review-comment.js +5 -0
- package/dist/review/suggestions/actions.js +60 -21
- package/dist/review/suggestions/store.d.ts +2 -0
- package/dist/review/suggestions/store.js +28 -0
- package/dist/secrets/actions/delete-api-key.js +5 -0
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-capabilities.js +13 -6
- package/dist/server/agent-chat/context-tools.js +63 -2
- package/dist/server/agent-chat-plugin.d.ts +2 -0
- package/dist/server/agent-chat-plugin.js +242 -54
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/analytics.d.ts +0 -1
- package/dist/server/analytics.js +81 -20
- package/dist/server/application-state-maintenance.d.ts +2 -0
- package/dist/server/application-state-maintenance.js +2 -0
- package/dist/server/attribution.d.ts +14 -0
- package/dist/server/attribution.js +62 -2
- package/dist/server/auth.js +7 -0
- package/dist/server/builder-api-auth.d.ts +7 -0
- package/dist/server/builder-api-auth.js +24 -0
- package/dist/server/builder-oauth.d.ts +5 -1
- package/dist/server/builder-oauth.js +5 -0
- package/dist/server/consent-route.d.ts +41 -0
- package/dist/server/consent-route.js +102 -0
- package/dist/server/core-routes-plugin.d.ts +1 -1
- package/dist/server/first-touch-route.d.ts +39 -0
- package/dist/server/first-touch-route.js +115 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +2 -1
- package/dist/server/queued-submission-inbox-drain.d.ts +9 -0
- package/dist/server/queued-submission-inbox-drain.js +12 -0
- package/dist/server/request-origin.d.ts +6 -0
- package/dist/server/request-origin.js +12 -0
- package/dist/settings/org-settings.d.ts +2 -1
- package/dist/settings/org-settings.js +4 -1
- package/dist/settings/store.d.ts +8 -0
- package/dist/settings/store.js +14 -5
- package/dist/shared/consent.d.ts +33 -0
- package/dist/shared/consent.js +149 -0
- package/dist/shared/first-touch-persistence.d.ts +31 -0
- package/dist/shared/first-touch-persistence.js +53 -0
- package/dist/sharing/actions/set-resource-visibility.js +5 -0
- package/dist/sharing/actions/share-resource.js +5 -0
- package/dist/sharing/actions/unshare-resource.js +5 -0
- package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
- package/dist/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
- package/dist/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
- package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
- package/dist/triggers/actions/manage-automation.d.ts +4 -4
- package/dist/usage/actions/get-usage-metrics.js +27 -4
- package/dist/usage/actions/manage-usage-alert.js +5 -0
- package/dist/vite/client.js +8 -6
- package/dist/workspace-connections/actions/bulk-update-workspace-user-groups.js +5 -0
- package/dist/workspace-connections/actions/delete-workspace-user-group.js +5 -0
- package/dist/workspace-connections/actions/upsert-workspace-user-group.js +5 -0
- package/docs/content/actions-access-control.mdx +8 -8
- package/docs/content/actions-defining.mdx +9 -8
- package/docs/content/deployment-environment-variables.mdx +1 -1
- package/docs/content/environment-variables.mdx +1 -1
- package/docs/content/template-design-developers.mdx +9 -9
- package/docs/content/template-design-features.mdx +1 -3
- package/docs/content/turn-into-app.mdx +4 -0
- package/package.json +6 -3
- package/src/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
- package/src/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
- package/src/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
- package/src/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { isDeepStrictEqual } from "node:util";
|
|
3
|
+
import { AGENT_NATIVE_SUBMISSION_EXPIRES_AT_METADATA_KEY, AGENT_NATIVE_SUBMISSION_TTL_MS_METADATA_KEY, MAX_AGENT_REQUEST_ATTACHMENT_DATA_CHARS, parseQueueMessageInput, persistableFilePart, fingerprintAgentSubmissionAttachment, submissionAttachmentsMatch, } from "@agent-native/agentkit/protocol";
|
|
3
4
|
import Ajv from "ajv";
|
|
4
5
|
import Ajv2020 from "ajv/dist/2020.js";
|
|
5
6
|
import { defineEventHandler, getHeader, setResponseHeader, setResponseStatus, getMethod, } from "h3";
|
|
@@ -22,6 +23,7 @@ import { describeAttachmentBytesVerdict, normalizeImageMediaType, reconcileImage
|
|
|
22
23
|
import { formatBase64CharBudget, MAX_INLINE_FILE_BASE64_CHARS, MAX_INLINE_IMAGE_BASE64_CHARS, } from "../file-upload/inline-attachment-limits.js";
|
|
23
24
|
import { claimOwnedAttachmentHydrationCandidate, createOwnedAttachmentHydrationBudget, describeOwnedImageReadFailure, hydrateOwnedImageUrl, } from "../file-upload/owned-attachment.js";
|
|
24
25
|
import { preUploadAttachments } from "../file-upload/pre-upload-attachments.js";
|
|
26
|
+
import { uploadFile } from "../file-upload/registry.js";
|
|
25
27
|
import { canonicalImageReferenceUrl } from "../file-upload/thread-image-history.js";
|
|
26
28
|
import { derivedTool, plainJsonSnapshot, UninterpretedSchema, UnusableSchemaError, usableInputSchema, } from "../json-schema/unusable-schema.js";
|
|
27
29
|
import { assertUsableSchema } from "../json-schema/usable-schema.js";
|
|
@@ -87,7 +89,7 @@ import { maybeCompactThread, buildObservationalContext, hasObservationalMemory,
|
|
|
87
89
|
import { ProcessorChain, TripWire, toolCallsFromContent, } from "./processors.js";
|
|
88
90
|
import { applyUncheckedDefaultModelReplacement } from "./provider-model-selection.js";
|
|
89
91
|
import { startRun, subscribeToRun, replayCompletedTurn, getActiveRunForThread, getActiveRunForThreadAsync, getRun, abortRun, abortRunDurably, abortRunAndTurnDurably, abortRunAtSafeBoundaryDurably, abortTurnByRefDurably, abortTurnDurably, getSlotHoldingRunId, tryClaimRunSlot, isHostedRuntime, resolveRunSoftTimeoutMs, resolveRunToolTimeoutCeilingMs, endsAfterToolResultWithoutAssistantFinal, endsDuringActionPreparation, } from "./run-manager.js";
|
|
90
|
-
import { writeLedgerEntry, readLedgerEntry, beginAgentExecutionStep, completeAgentExecutionStep, markAgentExecutionStepDispatched, markAgentExecutionStepUnknown, recordLateAgentExecutionStepOutcome, clearLedgerForThread, AgentTurnInitiatorMismatchError, AgentTurnInitiatorUnavailableError, insertRun, insertRunEvent, isTurnAborted, markRunAborted, updateRunHeartbeat, updateRunStatusIfRunning, updateRunTerminalStateIfRunning, setRunError, setRunTerminalReason, claimBackgroundRun, readBackgroundRunClaim, recordRunDiagnostic, countRunsForTurn, RUN_DIAG_STAGE, UNCLAIMED_BACKGROUND_RUN_GRACE_MS, turnRunLedgerExhausted, } from "./run-store.js";
|
|
92
|
+
import { writeLedgerEntry, readLedgerEntry, beginAgentExecutionStep, completeAgentExecutionStep, markAgentExecutionStepDispatched, markAgentExecutionStepUnknown, recordLateAgentExecutionStepOutcome, clearLedgerForThread, AgentTurnInitiatorMismatchError, AgentTurnInitiatorUnavailableError, insertRun, insertRunEvent, isRunAborted, isTurnAborted, markRunAborted, updateRunHeartbeat, updateRunStatusIfRunning, updateRunTerminalStateIfRunning, setRunError, setRunTerminalReason, claimBackgroundRun, readBackgroundRunClaim, recordRunDiagnostic, countRunsForTurn, RUN_DIAG_STAGE, UNCLAIMED_BACKGROUND_RUN_GRACE_MS, turnRunLedgerExhausted, } from "./run-store.js";
|
|
91
93
|
import { buildCurrentTimeUserContext } from "./runtime-context.js";
|
|
92
94
|
import { claimSetupResume, setupResumeRefusedRunId, } from "./setup-resume-claim.js";
|
|
93
95
|
import { getStrictToolInputValidator } from "./strict-tool-input.js";
|
|
@@ -619,6 +621,34 @@ function runSlotBusy(event, activeRunId) {
|
|
|
619
621
|
activeRunId,
|
|
620
622
|
};
|
|
621
623
|
}
|
|
624
|
+
function queuedSubmissionResponse(event, message, activeRunId) {
|
|
625
|
+
setResponseStatus(event, 202);
|
|
626
|
+
setResponseHeader(event, "Content-Type", "application/json");
|
|
627
|
+
return {
|
|
628
|
+
state: "queued",
|
|
629
|
+
message,
|
|
630
|
+
...(activeRunId ? { activeRunId } : {}),
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
const QUEUED_REASONING_EFFORTS = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
|
|
634
|
+
function effectiveQueuedRunOptions(options, model, effort, mode) {
|
|
635
|
+
const effective = options ? { ...options } : undefined;
|
|
636
|
+
let result = effective;
|
|
637
|
+
if (typeof model === "string" && model.trim()) {
|
|
638
|
+
result ??= {};
|
|
639
|
+
result.model = model;
|
|
640
|
+
}
|
|
641
|
+
if (typeof effort === "string" &&
|
|
642
|
+
QUEUED_REASONING_EFFORTS.has(effort)) {
|
|
643
|
+
result ??= {};
|
|
644
|
+
result.reasoningEffort = effort;
|
|
645
|
+
}
|
|
646
|
+
if (mode !== undefined) {
|
|
647
|
+
result ??= {};
|
|
648
|
+
result.mode = mode;
|
|
649
|
+
}
|
|
650
|
+
return result;
|
|
651
|
+
}
|
|
622
652
|
/**
|
|
623
653
|
* The error a chat turn answers with when no model credential is usable. A
|
|
624
654
|
* member whose org restricts personal API keys can't fix that by adding a key,
|
|
@@ -4606,6 +4636,31 @@ function notifyModelInputObserver(observer, messages) {
|
|
|
4606
4636
|
// coercion-ok: observer failures cannot change agent execution.
|
|
4607
4637
|
}
|
|
4608
4638
|
}
|
|
4639
|
+
export function createRunSafeBoundaryGuards(input) {
|
|
4640
|
+
return {
|
|
4641
|
+
beforeModelDispatch: async (dispatch) => {
|
|
4642
|
+
await input.flushEvents();
|
|
4643
|
+
const interruptResult = await input.interruptRequestedAtBoundary();
|
|
4644
|
+
if (input.signal.aborted || interruptResult !== "none") {
|
|
4645
|
+
return { started: false };
|
|
4646
|
+
}
|
|
4647
|
+
return { started: true, value: dispatch() };
|
|
4648
|
+
},
|
|
4649
|
+
beforeWrite: async () => {
|
|
4650
|
+
await input.flushEvents();
|
|
4651
|
+
const interruptResult = await input.interruptRequestedAtBoundary();
|
|
4652
|
+
if (input.signal.aborted || interruptResult !== "none") {
|
|
4653
|
+
throw new Error("Run aborted at a safe boundary");
|
|
4654
|
+
}
|
|
4655
|
+
},
|
|
4656
|
+
};
|
|
4657
|
+
}
|
|
4658
|
+
export async function confirmQueuedRunInterrupt(input) {
|
|
4659
|
+
if (await input.abort())
|
|
4660
|
+
return "aborted";
|
|
4661
|
+
await input.defer();
|
|
4662
|
+
return "pending";
|
|
4663
|
+
}
|
|
4609
4664
|
export async function runAgentLoop(opts) {
|
|
4610
4665
|
const { engine, systemPrompt: providedSystemPrompt, tools: providedTools, availableTools: providedAvailableTools, messages, actions, send, signal, } = opts;
|
|
4611
4666
|
// Every audit row this loop writes reads from this: each action's own, and
|
|
@@ -8084,15 +8139,118 @@ async function readTurnStartedAt(threadId, turnId) {
|
|
|
8084
8139
|
const startedAt = Number(raw);
|
|
8085
8140
|
return Number.isFinite(startedAt) && startedAt > 0 ? startedAt : null;
|
|
8086
8141
|
}
|
|
8142
|
+
function requestAttachmentIndexes(submission, attachments) {
|
|
8143
|
+
const unmatched = new Set(attachments.map((_, index) => index));
|
|
8144
|
+
for (const identity of submission.attachments ?? []) {
|
|
8145
|
+
const match = [...unmatched].find((index) => fingerprintAgentSubmissionAttachment(attachments[index], "file") ===
|
|
8146
|
+
identity.fingerprint);
|
|
8147
|
+
if (match === undefined)
|
|
8148
|
+
return null;
|
|
8149
|
+
unmatched.delete(match);
|
|
8150
|
+
}
|
|
8151
|
+
const requestIndexes = new Set();
|
|
8152
|
+
for (const identity of submission.requestAttachments ?? []) {
|
|
8153
|
+
const match = [...unmatched].find((index) => attachments[index]?.type === "image" &&
|
|
8154
|
+
fingerprintAgentSubmissionAttachment(attachments[index], "image") ===
|
|
8155
|
+
identity.fingerprint);
|
|
8156
|
+
if (match === undefined)
|
|
8157
|
+
return null;
|
|
8158
|
+
unmatched.delete(match);
|
|
8159
|
+
requestIndexes.add(match);
|
|
8160
|
+
}
|
|
8161
|
+
return requestIndexes;
|
|
8162
|
+
}
|
|
8163
|
+
async function queueableAttachments(attachments, ownerEmail, requestAttachmentIndexes) {
|
|
8164
|
+
const files = [];
|
|
8165
|
+
const requestFiles = [];
|
|
8166
|
+
for (const [index, attachment] of attachments.entries()) {
|
|
8167
|
+
if (attachment.displayOnly === true)
|
|
8168
|
+
continue;
|
|
8169
|
+
if (attachment.type !== "image" &&
|
|
8170
|
+
attachment.type !== "file" &&
|
|
8171
|
+
attachment.type !== "document") {
|
|
8172
|
+
return null;
|
|
8173
|
+
}
|
|
8174
|
+
if (typeof attachment.name !== "string") {
|
|
8175
|
+
return null;
|
|
8176
|
+
}
|
|
8177
|
+
const record = attachment;
|
|
8178
|
+
const mediaType = typeof attachment.contentType === "string" && attachment.contentType
|
|
8179
|
+
? attachment.contentType
|
|
8180
|
+
: typeof attachment.mediaType === "string"
|
|
8181
|
+
? attachment.mediaType
|
|
8182
|
+
: undefined;
|
|
8183
|
+
const inlineData = typeof attachment.data === "string"
|
|
8184
|
+
? attachment.data
|
|
8185
|
+
: typeof attachment.text === "string"
|
|
8186
|
+
? `data:${mediaType ?? "text/plain"};base64,${Buffer.from(attachment.text, "utf8").toString("base64")}`
|
|
8187
|
+
: typeof attachment.url === "string" &&
|
|
8188
|
+
attachment.url.startsWith("data:")
|
|
8189
|
+
? attachment.url
|
|
8190
|
+
: undefined;
|
|
8191
|
+
let part = persistableFilePart({
|
|
8192
|
+
type: "file",
|
|
8193
|
+
name: attachment.name,
|
|
8194
|
+
...(mediaType ? { mediaType } : {}),
|
|
8195
|
+
...(typeof attachment.url === "string" ? { url: attachment.url } : {}),
|
|
8196
|
+
...(typeof record.fileId === "string"
|
|
8197
|
+
? { fileId: record.fileId }
|
|
8198
|
+
: typeof record.id === "string"
|
|
8199
|
+
? { fileId: record.id }
|
|
8200
|
+
: {}),
|
|
8201
|
+
});
|
|
8202
|
+
if (!part.fileId &&
|
|
8203
|
+
inlineData &&
|
|
8204
|
+
(!part.url || !record.uploadProvider || record.storageUploadFailed)) {
|
|
8205
|
+
const parsedData = parseBase64DataUrl(inlineData);
|
|
8206
|
+
if (parsedData) {
|
|
8207
|
+
const uploaded = await uploadFile({
|
|
8208
|
+
data: new Uint8Array(Buffer.from(parsedData.data, "base64")),
|
|
8209
|
+
filename: attachment.name,
|
|
8210
|
+
mimeType: mediaType ?? parsedData.mediaType,
|
|
8211
|
+
ownerEmail: ownerEmail ?? undefined,
|
|
8212
|
+
});
|
|
8213
|
+
if (uploaded) {
|
|
8214
|
+
attachment.url = uploaded.url;
|
|
8215
|
+
attachment.uploadProvider = uploaded.provider;
|
|
8216
|
+
part = persistableFilePart({
|
|
8217
|
+
type: "file",
|
|
8218
|
+
name: attachment.name,
|
|
8219
|
+
...(mediaType ? { mediaType } : {}),
|
|
8220
|
+
url: uploaded.url,
|
|
8221
|
+
});
|
|
8222
|
+
}
|
|
8223
|
+
}
|
|
8224
|
+
}
|
|
8225
|
+
if (requestAttachmentIndexes.has(index)) {
|
|
8226
|
+
if (!part.url || !hasDurableAttachmentUrl(part.url))
|
|
8227
|
+
return null;
|
|
8228
|
+
const referenceUrl = attachment.referenceUrl;
|
|
8229
|
+
if (referenceUrl && !hasDurableAttachmentUrl(referenceUrl))
|
|
8230
|
+
return null;
|
|
8231
|
+
requestFiles.push({
|
|
8232
|
+
type: "image",
|
|
8233
|
+
name: attachment.name,
|
|
8234
|
+
...(mediaType ? { contentType: mediaType } : {}),
|
|
8235
|
+
url: part.url,
|
|
8236
|
+
...(referenceUrl ? { referenceUrl } : {}),
|
|
8237
|
+
});
|
|
8238
|
+
continue;
|
|
8239
|
+
}
|
|
8240
|
+
if (!part.url && !part.fileId)
|
|
8241
|
+
return null;
|
|
8242
|
+
files.push(part);
|
|
8243
|
+
}
|
|
8244
|
+
return { attachments: files, requestAttachments: requestFiles };
|
|
8245
|
+
}
|
|
8087
8246
|
function queuedPromotionRecord(value) {
|
|
8088
8247
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
8089
8248
|
? value
|
|
8090
8249
|
: null;
|
|
8091
8250
|
}
|
|
8092
8251
|
function validateQueuedPromotionRequestAttachments(value) {
|
|
8093
|
-
if (!Array.isArray(value)
|
|
8252
|
+
if (!Array.isArray(value))
|
|
8094
8253
|
return null;
|
|
8095
|
-
}
|
|
8096
8254
|
let totalDataChars = 0;
|
|
8097
8255
|
const attachments = [];
|
|
8098
8256
|
for (const entry of value) {
|
|
@@ -8141,7 +8299,8 @@ function validateQueuedPromotionRequestAttachments(value) {
|
|
|
8141
8299
|
}
|
|
8142
8300
|
return attachments;
|
|
8143
8301
|
}
|
|
8144
|
-
|
|
8302
|
+
/** @internal exported for unit tests only */
|
|
8303
|
+
export async function readAdmittedQueuedMessagePromotion(opts) {
|
|
8145
8304
|
const messageId = typeof opts.messageId === "string" ? opts.messageId.trim() : "";
|
|
8146
8305
|
const claimId = typeof opts.claimId === "string" ? opts.claimId.trim() : "";
|
|
8147
8306
|
if (!opts.ownerEmail ||
|
|
@@ -8197,6 +8356,9 @@ async function readAdmittedQueuedMessagePromotion(opts) {
|
|
|
8197
8356
|
const options = hasOwn(queuedMessage, "options")
|
|
8198
8357
|
? queuedMessage.options
|
|
8199
8358
|
: undefined;
|
|
8359
|
+
const references = hasOwn(queuedMessage, "references")
|
|
8360
|
+
? queuedMessage.references
|
|
8361
|
+
: undefined;
|
|
8200
8362
|
if ((attachments !== undefined && !Array.isArray(attachments)) ||
|
|
8201
8363
|
(Array.isArray(attachments) &&
|
|
8202
8364
|
attachments.some((attachment) => {
|
|
@@ -8208,14 +8370,19 @@ async function readAdmittedQueuedMessagePromotion(opts) {
|
|
|
8208
8370
|
(metadata !== undefined &&
|
|
8209
8371
|
(!metadata || typeof metadata !== "object" || Array.isArray(metadata))) ||
|
|
8210
8372
|
(options !== undefined &&
|
|
8211
|
-
(!options || typeof options !== "object" || Array.isArray(options)))
|
|
8373
|
+
(!options || typeof options !== "object" || Array.isArray(options))) ||
|
|
8374
|
+
(references !== undefined && !Array.isArray(references))) {
|
|
8212
8375
|
return null;
|
|
8213
8376
|
}
|
|
8377
|
+
parseQueueMessageInput({ ...queuedMessage, threadId: opts.threadId }, "queuedMessagePromotion", { allowLegacyQueueCount: true });
|
|
8214
8378
|
return {
|
|
8215
8379
|
id: messageId,
|
|
8216
8380
|
text: queuedMessage.text,
|
|
8217
8381
|
...(Array.isArray(attachments) ? { attachments } : {}),
|
|
8218
8382
|
...(requestAttachments ? { requestAttachments } : {}),
|
|
8383
|
+
...(Array.isArray(references)
|
|
8384
|
+
? { references: references }
|
|
8385
|
+
: {}),
|
|
8219
8386
|
...(metadata ? { metadata: metadata } : {}),
|
|
8220
8387
|
...(options ? { options: options } : {}),
|
|
8221
8388
|
};
|
|
@@ -8302,6 +8469,7 @@ export function queuedPromotionAttachments(attachments, requestAttachments = [])
|
|
|
8302
8469
|
: {}),
|
|
8303
8470
|
...(data ? { data } : {}),
|
|
8304
8471
|
...(imageUrl ? { url: imageUrl } : {}),
|
|
8472
|
+
...(referenceUrl ? { referenceUrl } : {}),
|
|
8305
8473
|
...(fileId ? { id: fileId } : {}),
|
|
8306
8474
|
};
|
|
8307
8475
|
const replacementIndex = matchingIndex >= 0 && matchingIndex !== referenceIndex
|
|
@@ -8414,6 +8582,7 @@ export async function chainServerDrivenContinuation(opts) {
|
|
|
8414
8582
|
recordRunDiagnostic: opts.deps?.recordRunDiagnostic ?? recordRunDiagnostic,
|
|
8415
8583
|
markBackgroundContinuationChunkTerminal: opts.deps?.markBackgroundContinuationChunkTerminal ??
|
|
8416
8584
|
markBackgroundContinuationChunkTerminal,
|
|
8585
|
+
isRunAborted: opts.deps?.isRunAborted ?? isRunAborted,
|
|
8417
8586
|
generateRunId: opts.deps?.generateRunId ?? generateRunId,
|
|
8418
8587
|
sleep: opts.deps?.sleep ??
|
|
8419
8588
|
((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
|
|
@@ -8497,9 +8666,20 @@ export async function chainServerDrivenContinuation(opts) {
|
|
|
8497
8666
|
delete continuationBody.approvedToolCalls;
|
|
8498
8667
|
delete continuationBody.approvedToolCallAskIds;
|
|
8499
8668
|
delete continuationBody[AGENT_CHAT_BACKGROUND_RUN_FIELD];
|
|
8669
|
+
const markRunsAbortedOrThrow = async (...runIds) => {
|
|
8670
|
+
const results = await Promise.allSettled(runIds.map(async (targetRunId) => {
|
|
8671
|
+
if (await d.markRunAborted(targetRunId, "user"))
|
|
8672
|
+
return true;
|
|
8673
|
+
return await d.isRunAborted(targetRunId);
|
|
8674
|
+
}));
|
|
8675
|
+
const failedRunIds = results.flatMap((result, index) => result.status === "fulfilled" && result.value ? [] : [runIds[index]]);
|
|
8676
|
+
if (failedRunIds.length > 0) {
|
|
8677
|
+
throw new Error(`Could not confirm durable abort for continuation run(s): ${failedRunIds.join(", ")}`);
|
|
8678
|
+
}
|
|
8679
|
+
};
|
|
8500
8680
|
try {
|
|
8501
8681
|
if (await d.isTurnAborted(effectiveThreadId, effectiveTurnId)) {
|
|
8502
|
-
await
|
|
8682
|
+
await markRunsAbortedOrThrow(runId);
|
|
8503
8683
|
return;
|
|
8504
8684
|
}
|
|
8505
8685
|
await d
|
|
@@ -8527,9 +8707,7 @@ export async function chainServerDrivenContinuation(opts) {
|
|
|
8527
8707
|
console.error("[agent-chat] continuation insertRun failed; dispatching with inline body:", insertErr instanceof Error ? insertErr.message : insertErr);
|
|
8528
8708
|
}
|
|
8529
8709
|
if (await d.isTurnAborted(effectiveThreadId, effectiveTurnId)) {
|
|
8530
|
-
|
|
8531
|
-
await d.markRunAborted(nextRunId, "user").catch(() => { });
|
|
8532
|
-
await d.markRunAborted(runId, "user").catch(() => { });
|
|
8710
|
+
await markRunsAbortedOrThrow(...(nextRowInserted ? [nextRunId] : []), runId);
|
|
8533
8711
|
return;
|
|
8534
8712
|
}
|
|
8535
8713
|
const continuationTerminalEvent = {
|
|
@@ -8544,6 +8722,11 @@ export async function chainServerDrivenContinuation(opts) {
|
|
|
8544
8722
|
if (!terminalMarked) {
|
|
8545
8723
|
throw new Error(`Could not release run ${runId} for continuation ${nextRunId}`);
|
|
8546
8724
|
}
|
|
8725
|
+
if (await d.isTurnAborted(effectiveThreadId, effectiveTurnId)) {
|
|
8726
|
+
if (nextRowInserted)
|
|
8727
|
+
await markRunsAbortedOrThrow(nextRunId);
|
|
8728
|
+
return;
|
|
8729
|
+
}
|
|
8547
8730
|
run.continuationTerminalEvent = continuationTerminalEvent;
|
|
8548
8731
|
const dispatchBody = nextRowInserted
|
|
8549
8732
|
? {
|
|
@@ -8775,7 +8958,7 @@ export function createProductionAgentHandler(options) {
|
|
|
8775
8958
|
return { error: "Invalid request body" };
|
|
8776
8959
|
}
|
|
8777
8960
|
}
|
|
8778
|
-
const { message, history: submittedHistory = [], structuredHistory: submittedStructuredHistory, loadedSkillSlugs: requestedLoadedSkillSlugs, references: submittedReferences = [], threadId, attachments, displayMessage, parentId, queuedMessageId, queuedMessageClaimId, agentKitMessageId: requestedAgentKitMessageId, submissionPayload: requestedSubmissionPayload, internalContinuation: submittedInternalContinuation, autoContinueOfRunId: requestedAutoContinueOfRunId, continueOfRunId: requestedContinueOfRunId, turnId: requestTurnId, model: submittedModel, engine: submittedEngine, effort: submittedEffort, browserTabId, scope, harness: submittedHarness, trackInRunsTray, skipPendingSelectionContext, } = body;
|
|
8961
|
+
const { message, history: submittedHistory = [], structuredHistory: submittedStructuredHistory, loadedSkillSlugs: requestedLoadedSkillSlugs, references: submittedReferences = [], threadId, attachments, displayMessage, parentId, queuedMessageId, queuedMessageClaimId, agentKitMessageId: requestedAgentKitMessageId, submissionPayload: requestedSubmissionPayload, internalContinuation: submittedInternalContinuation, autoContinueOfRunId: requestedAutoContinueOfRunId, continueOfRunId: requestedContinueOfRunId, turnId: requestTurnId, model: submittedModel, engine: submittedEngine, effort: submittedEffort, options: submittedRunOptions, browserTabId, scope, harness: submittedHarness, trackInRunsTray, skipPendingSelectionContext, } = body;
|
|
8779
8962
|
let requestHistory = submittedHistory;
|
|
8780
8963
|
let requestStructuredHistory = submittedStructuredHistory;
|
|
8781
8964
|
let requestReferences = submittedReferences;
|
|
@@ -8784,6 +8967,11 @@ export function createProductionAgentHandler(options) {
|
|
|
8784
8967
|
let requestModel = submittedModel;
|
|
8785
8968
|
let requestEngine = submittedEngine;
|
|
8786
8969
|
let requestEffort = submittedEffort;
|
|
8970
|
+
let requestOptions = submittedRunOptions &&
|
|
8971
|
+
typeof submittedRunOptions === "object" &&
|
|
8972
|
+
!Array.isArray(submittedRunOptions)
|
|
8973
|
+
? submittedRunOptions
|
|
8974
|
+
: undefined;
|
|
8787
8975
|
let internalContinuation = submittedInternalContinuation;
|
|
8788
8976
|
let requestHarness = submittedHarness;
|
|
8789
8977
|
let requestSkipPendingSelectionContext = skipPendingSelectionContext;
|
|
@@ -8838,7 +9026,49 @@ export function createProductionAgentHandler(options) {
|
|
|
8838
9026
|
setResponseStatus(event, 400);
|
|
8839
9027
|
return { error: "submissionPayload does not match this message" };
|
|
8840
9028
|
}
|
|
8841
|
-
|
|
9029
|
+
let validatedSubmissionPayload;
|
|
9030
|
+
try {
|
|
9031
|
+
validatedSubmissionPayload = parseQueueMessageInput({
|
|
9032
|
+
threadId: candidate.threadId,
|
|
9033
|
+
id: candidate.id,
|
|
9034
|
+
text: candidate.text,
|
|
9035
|
+
submissionPayload: candidate,
|
|
9036
|
+
}, "submissionPayload").submissionPayload;
|
|
9037
|
+
}
|
|
9038
|
+
catch {
|
|
9039
|
+
setResponseStatus(event, 400);
|
|
9040
|
+
return { error: "Invalid submissionPayload" };
|
|
9041
|
+
}
|
|
9042
|
+
if (!validatedSubmissionPayload) {
|
|
9043
|
+
setResponseStatus(event, 400);
|
|
9044
|
+
return { error: "Invalid submissionPayload" };
|
|
9045
|
+
}
|
|
9046
|
+
submissionPayload = validatedSubmissionPayload;
|
|
9047
|
+
if (validatedSubmissionPayload.text !==
|
|
9048
|
+
(typeof message === "string" ? message : "") ||
|
|
9049
|
+
!isDeepStrictEqual(validatedSubmissionPayload.references ?? [], submittedReferences) ||
|
|
9050
|
+
!isDeepStrictEqual(validatedSubmissionPayload.options ?? {}, requestOptions ?? {})) {
|
|
9051
|
+
setResponseStatus(event, 400);
|
|
9052
|
+
return { error: "submissionPayload does not match this message" };
|
|
9053
|
+
}
|
|
9054
|
+
}
|
|
9055
|
+
let requestMode = body.mode === "plan" || requestOptions?.mode === "plan" ? "plan" : "act";
|
|
9056
|
+
requestOptions = effectiveQueuedRunOptions(requestOptions, requestModel, requestEffort, body.mode !== undefined || requestOptions?.mode !== undefined
|
|
9057
|
+
? requestMode
|
|
9058
|
+
: undefined);
|
|
9059
|
+
if (submissionPayload) {
|
|
9060
|
+
const metadata = submissionPayload.metadata === undefined && requestEngine === undefined
|
|
9061
|
+
? undefined
|
|
9062
|
+
: {
|
|
9063
|
+
...submissionPayload.metadata,
|
|
9064
|
+
...(requestEngine === undefined ? {} : { engine: requestEngine }),
|
|
9065
|
+
};
|
|
9066
|
+
submissionPayload = {
|
|
9067
|
+
...submissionPayload,
|
|
9068
|
+
...(requestOptions === undefined ? {} : { options: requestOptions }),
|
|
9069
|
+
...(metadata === undefined ? {} : { metadata }),
|
|
9070
|
+
};
|
|
9071
|
+
requestMetadata = normalizeSubmissionDeadlineMetadata(submissionPayload.metadata);
|
|
8842
9072
|
}
|
|
8843
9073
|
const backgroundRunMarker = preInjectedBody &&
|
|
8844
9074
|
body[AGENT_CHAT_BACKGROUND_RUN_FIELD] &&
|
|
@@ -8942,7 +9172,6 @@ export function createProductionAgentHandler(options) {
|
|
|
8942
9172
|
requestRunCtx.chatScope = requestChatScope;
|
|
8943
9173
|
requestRunCtx.isBackgroundWorker = isBackgroundWorker;
|
|
8944
9174
|
}
|
|
8945
|
-
let requestMode = body.mode === "plan" ? "plan" : "act";
|
|
8946
9175
|
const hasMessageText = typeof message === "string" && message.trim().length > 0;
|
|
8947
9176
|
let hasAttachments = Array.isArray(attachments) && attachments.length > 0;
|
|
8948
9177
|
if (!hasMessageText && !hasAttachments) {
|
|
@@ -8951,6 +9180,19 @@ export function createProductionAgentHandler(options) {
|
|
|
8951
9180
|
}
|
|
8952
9181
|
let requestMessage = hasMessageText ? message : "Use the attached context.";
|
|
8953
9182
|
let requestAttachments = Array.isArray(attachments) ? attachments : [];
|
|
9183
|
+
const submissionAttachmentsAreConsistent = submissionPayload !== undefined &&
|
|
9184
|
+
submissionAttachmentsMatch(submissionPayload, requestAttachments);
|
|
9185
|
+
if (submissionPayload && !submissionAttachmentsAreConsistent) {
|
|
9186
|
+
setResponseStatus(event, 400);
|
|
9187
|
+
return { error: "submissionPayload does not match this message" };
|
|
9188
|
+
}
|
|
9189
|
+
const submissionRequestAttachmentIndexes = submissionPayload
|
|
9190
|
+
? requestAttachmentIndexes(submissionPayload, requestAttachments)
|
|
9191
|
+
: new Set();
|
|
9192
|
+
if (!submissionRequestAttachmentIndexes) {
|
|
9193
|
+
setResponseStatus(event, 400);
|
|
9194
|
+
return { error: "submissionPayload does not match this message" };
|
|
9195
|
+
}
|
|
8954
9196
|
let attachmentHydrationBudget;
|
|
8955
9197
|
let requestDisplayMessage = displayMessage;
|
|
8956
9198
|
let requestContext = buildRecentUserRequestContext({
|
|
@@ -8969,6 +9211,211 @@ export function createProductionAgentHandler(options) {
|
|
|
8969
9211
|
anonymous: runRequestContext?.agentRunAnonymous === true,
|
|
8970
9212
|
}
|
|
8971
9213
|
: undefined;
|
|
9214
|
+
const busySubmissionQueueEligible = Boolean(submissionPayload &&
|
|
9215
|
+
agentKitMessageId &&
|
|
9216
|
+
threadId &&
|
|
9217
|
+
ownerEmail &&
|
|
9218
|
+
!internalContinuation &&
|
|
9219
|
+
!continueOf &&
|
|
9220
|
+
!queuedMessageId &&
|
|
9221
|
+
!queuedMessageClaimId &&
|
|
9222
|
+
!isBackgroundWorker &&
|
|
9223
|
+
submittedInternalContinuation !== true &&
|
|
9224
|
+
typeof requestedAutoContinueOfRunId !== "string" &&
|
|
9225
|
+
typeof requestedContinueOfRunId !== "string" &&
|
|
9226
|
+
!hasOwn(body, "approvedToolCalls") &&
|
|
9227
|
+
!hasOwn(body, "approvedToolCallAskIds") &&
|
|
9228
|
+
!hasOwn(body, "resume"));
|
|
9229
|
+
const busySubmissionAttachmentsAreQueueable = requestAttachments.every((attachment) => attachment.displayOnly === true ||
|
|
9230
|
+
((attachment.type === "image" ||
|
|
9231
|
+
attachment.type === "file" ||
|
|
9232
|
+
attachment.type === "document") &&
|
|
9233
|
+
typeof attachment.name === "string"));
|
|
9234
|
+
const tryAdmitBusySubmission = async () => {
|
|
9235
|
+
if (!submissionPayload ||
|
|
9236
|
+
!agentKitMessageId ||
|
|
9237
|
+
!threadId ||
|
|
9238
|
+
!ownerEmail ||
|
|
9239
|
+
internalContinuation ||
|
|
9240
|
+
continueOf ||
|
|
9241
|
+
queuedMessageId ||
|
|
9242
|
+
queuedMessageClaimId ||
|
|
9243
|
+
isBackgroundWorker ||
|
|
9244
|
+
submittedInternalContinuation === true ||
|
|
9245
|
+
typeof requestedAutoContinueOfRunId === "string" ||
|
|
9246
|
+
typeof requestedContinueOfRunId === "string" ||
|
|
9247
|
+
hasOwn(body, "approvedToolCalls") ||
|
|
9248
|
+
hasOwn(body, "approvedToolCallAskIds") ||
|
|
9249
|
+
hasOwn(body, "resume")) {
|
|
9250
|
+
return null;
|
|
9251
|
+
}
|
|
9252
|
+
const { resolveThreadAccess } = await import("../chat-threads/store.js");
|
|
9253
|
+
const accessibleThread = await resolveThreadAccess(ownerEmail, threadId, "editor", { orgId: getRequestOrgId() ?? undefined });
|
|
9254
|
+
if (!accessibleThread) {
|
|
9255
|
+
setResponseStatus(event, 404);
|
|
9256
|
+
return { error: "Thread not found" };
|
|
9257
|
+
}
|
|
9258
|
+
const attachmentsForQueue = await queueableAttachments(requestAttachments, ownerEmail, submissionRequestAttachmentIndexes);
|
|
9259
|
+
if (!attachmentsForQueue) {
|
|
9260
|
+
if (requestAttachments.some((attachment) => attachment.displayOnly !== true &&
|
|
9261
|
+
(attachment.type === "image" ||
|
|
9262
|
+
attachment.type === "file" ||
|
|
9263
|
+
attachment.type === "document"))) {
|
|
9264
|
+
setResponseStatus(event, 503);
|
|
9265
|
+
return {
|
|
9266
|
+
error: "The attachment could not be saved for later delivery",
|
|
9267
|
+
code: "queued_attachment_reference_unavailable",
|
|
9268
|
+
retryable: true,
|
|
9269
|
+
};
|
|
9270
|
+
}
|
|
9271
|
+
return null;
|
|
9272
|
+
}
|
|
9273
|
+
const queueText = typeof message === "string" && message.trim()
|
|
9274
|
+
? message
|
|
9275
|
+
: "Use the attached context.";
|
|
9276
|
+
let parsedMessage;
|
|
9277
|
+
try {
|
|
9278
|
+
parsedMessage = parseQueueMessageInput({
|
|
9279
|
+
threadId,
|
|
9280
|
+
id: agentKitMessageId,
|
|
9281
|
+
text: queueText,
|
|
9282
|
+
...(attachmentsForQueue.attachments.length
|
|
9283
|
+
? { attachments: attachmentsForQueue.attachments }
|
|
9284
|
+
: {}),
|
|
9285
|
+
...(attachmentsForQueue.requestAttachments.length
|
|
9286
|
+
? { requestAttachments: attachmentsForQueue.requestAttachments }
|
|
9287
|
+
: {}),
|
|
9288
|
+
...(submittedReferences.length
|
|
9289
|
+
? { references: submittedReferences }
|
|
9290
|
+
: {}),
|
|
9291
|
+
...(requestMetadata ? { metadata: requestMetadata } : {}),
|
|
9292
|
+
...(requestOptions ? { options: requestOptions } : {}),
|
|
9293
|
+
...(submissionPayload.interruptActiveRun === true
|
|
9294
|
+
? { interruptActiveRun: true }
|
|
9295
|
+
: {}),
|
|
9296
|
+
}, "agentChatSubmission");
|
|
9297
|
+
}
|
|
9298
|
+
catch {
|
|
9299
|
+
setResponseStatus(event, 400);
|
|
9300
|
+
return {
|
|
9301
|
+
error: "This submission cannot be saved for later delivery",
|
|
9302
|
+
code: "queued_submission_invalid",
|
|
9303
|
+
retryable: false,
|
|
9304
|
+
};
|
|
9305
|
+
}
|
|
9306
|
+
if (!parsedMessage.text.trim()) {
|
|
9307
|
+
setResponseStatus(event, 400);
|
|
9308
|
+
return {
|
|
9309
|
+
error: "This submission cannot be saved for later delivery",
|
|
9310
|
+
code: "queued_submission_invalid",
|
|
9311
|
+
retryable: false,
|
|
9312
|
+
};
|
|
9313
|
+
}
|
|
9314
|
+
const { mutateThreadQueuedMessages, QueuedSubmissionAdmissionError } = await import("../chat-threads/store.js");
|
|
9315
|
+
const requestContext = getRequestContext();
|
|
9316
|
+
const actor = {
|
|
9317
|
+
email: requestContext?.userEmail ?? ownerEmail,
|
|
9318
|
+
...(requestContext?.authUserId
|
|
9319
|
+
? { authUserId: requestContext.authUserId }
|
|
9320
|
+
: {}),
|
|
9321
|
+
...(requestContext?.identityAuthenticatedAtMs !== undefined
|
|
9322
|
+
? {
|
|
9323
|
+
identityAuthenticatedAtMs: requestContext.identityAuthenticatedAtMs,
|
|
9324
|
+
}
|
|
9325
|
+
: {}),
|
|
9326
|
+
...(requestContext?.userName ? { name: requestContext.userName } : {}),
|
|
9327
|
+
orgId: requestContext?.orgId ?? null,
|
|
9328
|
+
orgScope: requestContext?.orgScope ?? null,
|
|
9329
|
+
anonymous: requestContext?.agentRunAnonymous === true,
|
|
9330
|
+
};
|
|
9331
|
+
const queuedMessage = {
|
|
9332
|
+
...parsedMessage,
|
|
9333
|
+
id: agentKitMessageId,
|
|
9334
|
+
threadId,
|
|
9335
|
+
createdAt: new Date().toISOString(),
|
|
9336
|
+
...(attachmentsForQueue.attachments.length
|
|
9337
|
+
? { attachments: attachmentsForQueue.attachments }
|
|
9338
|
+
: {}),
|
|
9339
|
+
...(attachmentsForQueue.requestAttachments.length
|
|
9340
|
+
? { requestAttachments: attachmentsForQueue.requestAttachments }
|
|
9341
|
+
: {}),
|
|
9342
|
+
};
|
|
9343
|
+
let result;
|
|
9344
|
+
try {
|
|
9345
|
+
result = await mutateThreadQueuedMessages(threadId, {
|
|
9346
|
+
type: "append",
|
|
9347
|
+
message: queuedMessage,
|
|
9348
|
+
hashInput: submissionPayload,
|
|
9349
|
+
}, { actor });
|
|
9350
|
+
}
|
|
9351
|
+
catch (error) {
|
|
9352
|
+
if (!(error instanceof QueuedSubmissionAdmissionError))
|
|
9353
|
+
throw error;
|
|
9354
|
+
setResponseStatus(event, 409);
|
|
9355
|
+
return {
|
|
9356
|
+
error: "This message ID is no longer available for submission",
|
|
9357
|
+
code: error.code,
|
|
9358
|
+
retryable: false,
|
|
9359
|
+
};
|
|
9360
|
+
}
|
|
9361
|
+
if (!result)
|
|
9362
|
+
return null;
|
|
9363
|
+
if (result.receiptUnavailable) {
|
|
9364
|
+
setResponseStatus(event, 503);
|
|
9365
|
+
return {
|
|
9366
|
+
error: "The queued submission receipt could not be saved",
|
|
9367
|
+
code: "queued_submission_receipt_unavailable",
|
|
9368
|
+
retryable: true,
|
|
9369
|
+
};
|
|
9370
|
+
}
|
|
9371
|
+
if (result.receiptConflict) {
|
|
9372
|
+
setResponseStatus(event, 409);
|
|
9373
|
+
return {
|
|
9374
|
+
error: "This message ID was already used for a different submission",
|
|
9375
|
+
code: "queued_message_id_conflict",
|
|
9376
|
+
retryable: false,
|
|
9377
|
+
};
|
|
9378
|
+
}
|
|
9379
|
+
if (result.submissionExpired) {
|
|
9380
|
+
setResponseStatus(event, 409);
|
|
9381
|
+
return {
|
|
9382
|
+
error: "This submission expired before it could be queued",
|
|
9383
|
+
code: "submission_expired",
|
|
9384
|
+
retryable: false,
|
|
9385
|
+
};
|
|
9386
|
+
}
|
|
9387
|
+
if (result.alreadySubmitted && result.submittedRunId) {
|
|
9388
|
+
const stream = subscribeToRun(result.submittedRunId, 0);
|
|
9389
|
+
if (!stream) {
|
|
9390
|
+
setResponseStatus(event, 503);
|
|
9391
|
+
return {
|
|
9392
|
+
error: "The accepted submission run is no longer replayable",
|
|
9393
|
+
code: "queued_message_run_unavailable",
|
|
9394
|
+
retryable: true,
|
|
9395
|
+
};
|
|
9396
|
+
}
|
|
9397
|
+
setResponseHeader(event, "Content-Type", "text/event-stream");
|
|
9398
|
+
setResponseHeader(event, "Cache-Control", "no-cache");
|
|
9399
|
+
setResponseHeader(event, "Connection", "keep-alive");
|
|
9400
|
+
setResponseHeader(event, "X-Run-Id", result.submittedRunId);
|
|
9401
|
+
setResponseHeader(event, "X-Dispatch-Mode", "replay");
|
|
9402
|
+
return stream;
|
|
9403
|
+
}
|
|
9404
|
+
if (!result.message) {
|
|
9405
|
+
setResponseStatus(event, 503);
|
|
9406
|
+
return {
|
|
9407
|
+
error: "The queued submission receipt could not be read",
|
|
9408
|
+
code: "queued_submission_receipt_unavailable",
|
|
9409
|
+
retryable: true,
|
|
9410
|
+
};
|
|
9411
|
+
}
|
|
9412
|
+
return queuedSubmissionResponse(event, {
|
|
9413
|
+
...result.message,
|
|
9414
|
+
id: agentKitMessageId,
|
|
9415
|
+
threadId,
|
|
9416
|
+
createdAt: result.message.createdAt ?? queuedMessage.createdAt,
|
|
9417
|
+
}, await getSlotHoldingRunId(threadId));
|
|
9418
|
+
};
|
|
8972
9419
|
if (submissionPayload &&
|
|
8973
9420
|
ownerEmail &&
|
|
8974
9421
|
threadId &&
|
|
@@ -8976,7 +9423,7 @@ export function createProductionAgentHandler(options) {
|
|
|
8976
9423
|
!queuedMessageId &&
|
|
8977
9424
|
!queuedMessageClaimId &&
|
|
8978
9425
|
!isBackgroundWorker) {
|
|
8979
|
-
const { getQueuedSubmissionReceipt, hashQueuedSubmissionPayload, resolveThreadAccess, } = await import("../chat-threads/store.js");
|
|
9426
|
+
const { getQueuedSubmissionReceipt, getQueuedSubmissionReceiptStatus, hashQueuedSubmissionPayload, resolveThreadAccess, } = await import("../chat-threads/store.js");
|
|
8980
9427
|
const receipt = await getQueuedSubmissionReceipt(threadId, String(submissionPayload.id));
|
|
8981
9428
|
if (receipt) {
|
|
8982
9429
|
const accessibleThread = await resolveThreadAccess(ownerEmail, threadId, "editor", { orgId: getRequestOrgId() ?? undefined });
|
|
@@ -9002,8 +9449,23 @@ export function createProductionAgentHandler(options) {
|
|
|
9002
9449
|
retryable: false,
|
|
9003
9450
|
};
|
|
9004
9451
|
}
|
|
9005
|
-
|
|
9006
|
-
|
|
9452
|
+
let receiptState = receipt.state;
|
|
9453
|
+
let submittedRunId = receipt.submittedRunId;
|
|
9454
|
+
if (receipt.state === "queued") {
|
|
9455
|
+
const status = await getQueuedSubmissionReceiptStatus(threadId, receipt.messageId);
|
|
9456
|
+
if (!status) {
|
|
9457
|
+
setResponseStatus(event, 503);
|
|
9458
|
+
return {
|
|
9459
|
+
error: "The queued submission receipt could not be read",
|
|
9460
|
+
code: "queued_submission_receipt_unavailable",
|
|
9461
|
+
retryable: true,
|
|
9462
|
+
};
|
|
9463
|
+
}
|
|
9464
|
+
receiptState = status.state;
|
|
9465
|
+
submittedRunId = status.submittedRunId;
|
|
9466
|
+
}
|
|
9467
|
+
if (receiptState === "submitted") {
|
|
9468
|
+
if (!submittedRunId) {
|
|
9007
9469
|
setResponseStatus(event, 503);
|
|
9008
9470
|
return {
|
|
9009
9471
|
error: "The accepted submission has no replayable run",
|
|
@@ -9011,7 +9473,7 @@ export function createProductionAgentHandler(options) {
|
|
|
9011
9473
|
retryable: true,
|
|
9012
9474
|
};
|
|
9013
9475
|
}
|
|
9014
|
-
const stream = subscribeToRun(
|
|
9476
|
+
const stream = subscribeToRun(submittedRunId, 0);
|
|
9015
9477
|
if (!stream) {
|
|
9016
9478
|
setResponseStatus(event, 503);
|
|
9017
9479
|
return {
|
|
@@ -9023,12 +9485,26 @@ export function createProductionAgentHandler(options) {
|
|
|
9023
9485
|
setResponseHeader(event, "Content-Type", "text/event-stream");
|
|
9024
9486
|
setResponseHeader(event, "Cache-Control", "no-cache");
|
|
9025
9487
|
setResponseHeader(event, "Connection", "keep-alive");
|
|
9026
|
-
setResponseHeader(event, "X-Run-Id",
|
|
9488
|
+
setResponseHeader(event, "X-Run-Id", submittedRunId);
|
|
9027
9489
|
setResponseHeader(event, "X-Dispatch-Mode", "replay");
|
|
9028
9490
|
return stream;
|
|
9029
9491
|
}
|
|
9030
|
-
if (
|
|
9031
|
-
|
|
9492
|
+
if (receiptState === "queued") {
|
|
9493
|
+
if (!receipt.message) {
|
|
9494
|
+
setResponseStatus(event, 503);
|
|
9495
|
+
return {
|
|
9496
|
+
error: "The queued submission receipt has no replayable message",
|
|
9497
|
+
code: "queued_submission_receipt_unavailable",
|
|
9498
|
+
retryable: true,
|
|
9499
|
+
};
|
|
9500
|
+
}
|
|
9501
|
+
return queuedSubmissionResponse(event, {
|
|
9502
|
+
...receipt.message,
|
|
9503
|
+
id: receipt.messageId,
|
|
9504
|
+
threadId,
|
|
9505
|
+
createdAt: receipt.message.createdAt ??
|
|
9506
|
+
new Date(receipt.createdAt).toISOString(),
|
|
9507
|
+
}, await getSlotHoldingRunId(threadId));
|
|
9032
9508
|
}
|
|
9033
9509
|
setResponseStatus(event, 409);
|
|
9034
9510
|
return {
|
|
@@ -9153,6 +9629,9 @@ export function createProductionAgentHandler(options) {
|
|
|
9153
9629
|
retryable: false,
|
|
9154
9630
|
};
|
|
9155
9631
|
}
|
|
9632
|
+
const isAuthorizedApprovalContinuation = Boolean(submittedInternalContinuation === true &&
|
|
9633
|
+
requestedApprovedToolCallAskIds?.length &&
|
|
9634
|
+
resolvedApprovalTurnId);
|
|
9156
9635
|
// The continuation marker is client-controlled. Defer setup admission only
|
|
9157
9636
|
// for automatic successors when the named stop and turn can be checked
|
|
9158
9637
|
// under the run-slot lock. A user's manual Continue starts new work and
|
|
@@ -9184,7 +9663,8 @@ export function createProductionAgentHandler(options) {
|
|
|
9184
9663
|
requestDisplayMessage = admittedQueuedMessage.text;
|
|
9185
9664
|
requestAttachments = queuedPromotionAttachments(admittedQueuedMessage.attachments ?? [], admittedQueuedMessage.requestAttachments);
|
|
9186
9665
|
hasAttachments = requestAttachments.length > 0;
|
|
9187
|
-
requestReferences = [];
|
|
9666
|
+
requestReferences = admittedQueuedMessage.references ?? [];
|
|
9667
|
+
requestOptions = promotionOptions;
|
|
9188
9668
|
requestHistory = [];
|
|
9189
9669
|
requestStructuredHistory = undefined;
|
|
9190
9670
|
internalContinuation = false;
|
|
@@ -9217,6 +9697,7 @@ export function createProductionAgentHandler(options) {
|
|
|
9217
9697
|
mutableBody.history = requestHistory;
|
|
9218
9698
|
delete mutableBody.structuredHistory;
|
|
9219
9699
|
mutableBody.metadata = requestMetadata;
|
|
9700
|
+
mutableBody.options = requestOptions;
|
|
9220
9701
|
mutableBody.model = requestModel;
|
|
9221
9702
|
if (requestEngine === undefined) {
|
|
9222
9703
|
delete mutableBody.engine;
|
|
@@ -9231,7 +9712,6 @@ export function createProductionAgentHandler(options) {
|
|
|
9231
9712
|
delete mutableBody.continueOfRunId;
|
|
9232
9713
|
delete mutableBody.harness;
|
|
9233
9714
|
delete mutableBody.parentId;
|
|
9234
|
-
delete mutableBody.options;
|
|
9235
9715
|
delete mutableBody.skipPendingSelectionContext;
|
|
9236
9716
|
}
|
|
9237
9717
|
const recordUnstartedTurn = async (failure) => {
|
|
@@ -9301,6 +9781,14 @@ export function createProductionAgentHandler(options) {
|
|
|
9301
9781
|
}
|
|
9302
9782
|
}
|
|
9303
9783
|
setupMark("aiGate");
|
|
9784
|
+
if (hasOwn(body, "queuedMessageClaimId") && !admittedQueuedMessage) {
|
|
9785
|
+
setResponseStatus(event, 409);
|
|
9786
|
+
return {
|
|
9787
|
+
error: "This queued message can no longer be promoted",
|
|
9788
|
+
code: "queued_message_claim_invalid",
|
|
9789
|
+
retryable: false,
|
|
9790
|
+
};
|
|
9791
|
+
}
|
|
9304
9792
|
const contextPrefetchDeadlineAt = Date.now() + 1_300;
|
|
9305
9793
|
const preparedRequest = await options.prepareRequest?.({
|
|
9306
9794
|
event,
|
|
@@ -9489,18 +9977,23 @@ export function createProductionAgentHandler(options) {
|
|
|
9489
9977
|
}
|
|
9490
9978
|
}
|
|
9491
9979
|
workerStep("db_request_ctx");
|
|
9980
|
+
if (hasAttachments &&
|
|
9981
|
+
threadId &&
|
|
9982
|
+
!isBackgroundWorker &&
|
|
9983
|
+
requestAttachments.some((attachment) => attachment.displayOnly !== true &&
|
|
9984
|
+
(attachment.type === "image" ||
|
|
9985
|
+
attachment.type === "file" ||
|
|
9986
|
+
attachment.type === "document"))) {
|
|
9987
|
+
const activeRunId = await getSlotHoldingRunId(threadId);
|
|
9988
|
+
if (activeRunId &&
|
|
9989
|
+
(!busySubmissionQueueEligible || !busySubmissionAttachmentsAreQueueable)) {
|
|
9990
|
+
return runSlotBusy(event, activeRunId);
|
|
9991
|
+
}
|
|
9992
|
+
}
|
|
9492
9993
|
workerStep("attach_start");
|
|
9493
9994
|
if (hasAttachments &&
|
|
9494
9995
|
requestAttachments.some((a) => a.displayOnly !== true &&
|
|
9495
9996
|
(a.type === "image" || a.type === "file" || a.type === "document"))) {
|
|
9496
|
-
// A busy thread refuses this message (409) and the client sends it again
|
|
9497
|
-
// once the thread frees up; uploading first would store every
|
|
9498
|
-
// attachment again on each refusal.
|
|
9499
|
-
if (threadId && !isBackgroundWorker) {
|
|
9500
|
-
const activeRunId = await getSlotHoldingRunId(threadId);
|
|
9501
|
-
if (activeRunId)
|
|
9502
|
-
return runSlotBusy(event, activeRunId);
|
|
9503
|
-
}
|
|
9504
9997
|
try {
|
|
9505
9998
|
attachmentHydrationBudget ??= createOwnedAttachmentHydrationBudget();
|
|
9506
9999
|
const preUpload = await preUploadAttachments({
|
|
@@ -9521,6 +10014,15 @@ export function createProductionAgentHandler(options) {
|
|
|
9521
10014
|
? `${requestMessage}\n\n${describeAttachmentPreUploadWarning()}`
|
|
9522
10015
|
: describeAttachmentPreUploadWarning();
|
|
9523
10016
|
}
|
|
10017
|
+
if (threadId && !isBackgroundWorker) {
|
|
10018
|
+
const activeRunId = await getSlotHoldingRunId(threadId);
|
|
10019
|
+
if (activeRunId) {
|
|
10020
|
+
const queued = await tryAdmitBusySubmission();
|
|
10021
|
+
if (queued !== null)
|
|
10022
|
+
return queued;
|
|
10023
|
+
return runSlotBusy(event, activeRunId);
|
|
10024
|
+
}
|
|
10025
|
+
}
|
|
9524
10026
|
}
|
|
9525
10027
|
const textAttachmentResourceMap = new Map();
|
|
9526
10028
|
if (hasAttachments && threadId) {
|
|
@@ -10273,6 +10775,11 @@ export function createProductionAgentHandler(options) {
|
|
|
10273
10775
|
}
|
|
10274
10776
|
let slot;
|
|
10275
10777
|
try {
|
|
10778
|
+
const runThreadId = threadId;
|
|
10779
|
+
const shouldPreserveQueuedOrder = Boolean(!isAuthorizedApprovalContinuation &&
|
|
10780
|
+
!queuedMessageId &&
|
|
10781
|
+
!queuedMessageClaimId &&
|
|
10782
|
+
!isBackgroundWorker);
|
|
10276
10783
|
slot = await tryClaimRunSlot(threadId, runId, undefined, {
|
|
10277
10784
|
turnId: effectiveTurnId,
|
|
10278
10785
|
...(turnInitiator ? { turnInitiator } : {}),
|
|
@@ -10288,6 +10795,14 @@ export function createProductionAgentHandler(options) {
|
|
|
10288
10795
|
? { dispatchPayload: durableDispatchPayload }
|
|
10289
10796
|
: {}),
|
|
10290
10797
|
...(continueOf ? { continueOf } : {}),
|
|
10798
|
+
...(shouldPreserveQueuedOrder
|
|
10799
|
+
? {
|
|
10800
|
+
hasPendingQueuedSubmission: async (tx) => {
|
|
10801
|
+
const { hasPendingQueuedSubmissionReceipt } = await import("../chat-threads/store.js");
|
|
10802
|
+
return hasPendingQueuedSubmissionReceipt(tx, runThreadId);
|
|
10803
|
+
},
|
|
10804
|
+
}
|
|
10805
|
+
: {}),
|
|
10291
10806
|
});
|
|
10292
10807
|
}
|
|
10293
10808
|
catch (error) {
|
|
@@ -10323,6 +10838,15 @@ export function createProductionAgentHandler(options) {
|
|
|
10323
10838
|
}
|
|
10324
10839
|
if (!slot.claimed) {
|
|
10325
10840
|
await setupResumeClaim?.release();
|
|
10841
|
+
if (slot.queuedSubmissionPending) {
|
|
10842
|
+
const queued = await tryAdmitBusySubmission();
|
|
10843
|
+
if (queued !== null)
|
|
10844
|
+
return queued;
|
|
10845
|
+
return runSlotBusy(event, null);
|
|
10846
|
+
}
|
|
10847
|
+
const queued = await tryAdmitBusySubmission();
|
|
10848
|
+
if (queued !== null)
|
|
10849
|
+
return queued;
|
|
10326
10850
|
return runSlotBusy(event, slot.activeRunId);
|
|
10327
10851
|
}
|
|
10328
10852
|
foregroundRunRowInserted = true;
|
|
@@ -10891,6 +11415,77 @@ export function createProductionAgentHandler(options) {
|
|
|
10891
11415
|
rawSend(event);
|
|
10892
11416
|
updateTrackedProgressFromEvent(event);
|
|
10893
11417
|
};
|
|
11418
|
+
const interruptQueuedRunAtBoundary = async () => {
|
|
11419
|
+
if (!threadId)
|
|
11420
|
+
return "none";
|
|
11421
|
+
const { clearQueuedSubmissionInterruptRun, listQueuedSubmissionReceipts, mutateThreadQueuedMessages, recordQueuedSubmissionInterruptRun, retryQueuedSubmissionReceipt, } = await import("../chat-threads/store.js");
|
|
11422
|
+
const pending = await listQueuedSubmissionReceipts({
|
|
11423
|
+
limit: 25,
|
|
11424
|
+
threadId,
|
|
11425
|
+
interruptActiveRun: true,
|
|
11426
|
+
});
|
|
11427
|
+
for (const receipt of pending) {
|
|
11428
|
+
if (receipt.message?.interruptActiveRun !== true)
|
|
11429
|
+
continue;
|
|
11430
|
+
const claimId = randomUUID();
|
|
11431
|
+
let claimed = false;
|
|
11432
|
+
try {
|
|
11433
|
+
const claim = await mutateThreadQueuedMessages(threadId, {
|
|
11434
|
+
type: "claimFromInbox",
|
|
11435
|
+
receipt,
|
|
11436
|
+
claimId,
|
|
11437
|
+
});
|
|
11438
|
+
if (!claim?.claimedMessage)
|
|
11439
|
+
continue;
|
|
11440
|
+
claimed = true;
|
|
11441
|
+
if (receipt.interruptRunId &&
|
|
11442
|
+
receipt.interruptRunId !== runId) {
|
|
11443
|
+
const { getRunById } = await import("./run-store.js");
|
|
11444
|
+
const interruptedRun = await getRunById(receipt.interruptRunId);
|
|
11445
|
+
if (interruptedRun?.status === "running")
|
|
11446
|
+
continue;
|
|
11447
|
+
const cleared = await clearQueuedSubmissionInterruptRun({
|
|
11448
|
+
threadId,
|
|
11449
|
+
messageId: receipt.messageId,
|
|
11450
|
+
runId: receipt.interruptRunId,
|
|
11451
|
+
claimId,
|
|
11452
|
+
});
|
|
11453
|
+
if (!cleared)
|
|
11454
|
+
continue;
|
|
11455
|
+
}
|
|
11456
|
+
if (!(await recordQueuedSubmissionInterruptRun({
|
|
11457
|
+
threadId,
|
|
11458
|
+
messageId: receipt.messageId,
|
|
11459
|
+
runId,
|
|
11460
|
+
claimId,
|
|
11461
|
+
}))) {
|
|
11462
|
+
continue;
|
|
11463
|
+
}
|
|
11464
|
+
const aborted = await confirmQueuedRunInterrupt({
|
|
11465
|
+
abort: () => abortRunAtSafeBoundaryDurably(runId, "user"),
|
|
11466
|
+
defer: () => retryQueuedSubmissionReceipt(threadId, receipt.messageId, Date.now() + 10_000, { claimId }),
|
|
11467
|
+
});
|
|
11468
|
+
if (aborted === "pending")
|
|
11469
|
+
return "pending";
|
|
11470
|
+
}
|
|
11471
|
+
finally {
|
|
11472
|
+
if (claimed) {
|
|
11473
|
+
await mutateThreadQueuedMessages(threadId, {
|
|
11474
|
+
type: "release",
|
|
11475
|
+
messageId: receipt.messageId,
|
|
11476
|
+
claimId,
|
|
11477
|
+
});
|
|
11478
|
+
}
|
|
11479
|
+
}
|
|
11480
|
+
return "aborted";
|
|
11481
|
+
}
|
|
11482
|
+
return "none";
|
|
11483
|
+
};
|
|
11484
|
+
const { beforeModelDispatch, beforeWrite } = createRunSafeBoundaryGuards({
|
|
11485
|
+
signal,
|
|
11486
|
+
flushEvents: control.flushEvents,
|
|
11487
|
+
interruptRequestedAtBoundary: interruptQueuedRunAtBoundary,
|
|
11488
|
+
});
|
|
10894
11489
|
if (selfChainBudget?.skipToBoundary) {
|
|
10895
11490
|
await recordRunDiagnostic(runId, RUN_DIAG_STAGE.workerSetupStep, `self_chain_budget_exhausted elapsed=${Date.now() - setupT0}ms`).catch(() => { });
|
|
10896
11491
|
send({ type: "auto_continue", reason: "run_timeout" });
|
|
@@ -10988,7 +11583,8 @@ export function createProductionAgentHandler(options) {
|
|
|
10988
11583
|
threadId: effectiveThreadId,
|
|
10989
11584
|
turnId: effectiveTurnId,
|
|
10990
11585
|
durableStepIdForToolCall: namespacedDurableStepId,
|
|
10991
|
-
|
|
11586
|
+
beforeModelDispatch,
|
|
11587
|
+
beforeWrite,
|
|
10992
11588
|
unknownOutcomes,
|
|
10993
11589
|
internalContinuation,
|
|
10994
11590
|
...(shouldRecoverCompletedExecutionSteps
|
|
@@ -11161,7 +11757,8 @@ export function createProductionAgentHandler(options) {
|
|
|
11161
11757
|
: {}),
|
|
11162
11758
|
systemSections: contextXraySystemSections,
|
|
11163
11759
|
actions: requestActions,
|
|
11164
|
-
|
|
11760
|
+
beforeModelDispatch,
|
|
11761
|
+
beforeWrite,
|
|
11165
11762
|
unknownOutcomes,
|
|
11166
11763
|
internalContinuation,
|
|
11167
11764
|
send,
|