@agent-native/core 0.213.1 → 0.216.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/appearance/actions/get-theme-family.d.ts +8 -0
- package/dist/appearance/actions/get-theme-family.js +38 -0
- package/dist/appearance/actions/set-theme-family.d.ts +7 -0
- package/dist/appearance/actions/set-theme-family.js +33 -0
- package/dist/appearance/theme-family.d.ts +13 -0
- package/dist/appearance/theme-family.js +38 -0
- package/dist/application-state/store.d.ts +5 -0
- package/dist/application-state/store.js +26 -0
- 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.js +167 -17
- 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 +36 -0
- package/dist/client/consent.js +283 -0
- package/dist/client/review/use-review.d.ts +2 -0
- package/dist/client/review/use-review.js +28 -1
- package/dist/client/sharing/useResourceAccessGate.d.ts +3 -2
- package/dist/client/sharing/useResourceAccessGate.js +9 -1
- package/dist/client/theme-family.d.ts +35 -0
- package/dist/client/theme-family.js +223 -0
- package/dist/client/theme.d.ts +1 -1
- package/dist/client/theme.js +5 -2
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- 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/connections/catalog.d.ts +5 -5
- package/dist/connections/catalog.js +22 -3
- package/dist/data-widgets/index.d.ts +374 -5
- package/dist/data-widgets/index.js +242 -11
- 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.js +5 -0
- package/dist/framework-tools.js +2 -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/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/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/observability/actions/save-observability-instruction-update.js +5 -0
- package/dist/observability/actions/save-observability-review-summary.js +5 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +19 -19
- package/dist/provider-api/actions/provider-api.d.ts +10 -10
- package/dist/provider-api/index.js +9 -2
- 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 +10 -10
- package/dist/server/action-discovery.js +8 -0
- package/dist/server/agent-chat/context-tools.js +105 -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/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/consent-route.d.ts +41 -0
- package/dist/server/consent-route.js +102 -0
- 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 +1 -0
- package/dist/server/index.js +1 -0
- 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 +31 -0
- package/dist/shared/consent.js +145 -0
- package/dist/shared/first-touch-persistence.d.ts +31 -0
- package/dist/shared/first-touch-persistence.js +53 -0
- package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
- 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/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/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 +4 -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
|
@@ -33,7 +33,7 @@ import { attachToolSearch } from "../agent/tool-search.js";
|
|
|
33
33
|
import { getAppConfig } from "../app-config/index.js";
|
|
34
34
|
import { readAppStateForCurrentTab } from "../application-state/script-helpers.js";
|
|
35
35
|
import { runChatThreadDataMigrations } from "../chat-threads/migrations.js";
|
|
36
|
-
import { InlineAttachmentDataNotPersistableError, QueuedSubmissionAdmissionError, adoptThreadScopeIfUnscoped, blockQueuedSubmissionReceipt, clearQueuedSubmissionInterruptRun, createThread, forkThread, getThread, getQueuedSubmissionReceipt, listQueuedSubmissionReceipts, markQueuedSubmissionSubmitted, queuedSubmissionBehaviorMatches, recordQueuedSubmissionInterruptRun, renewQueuedSubmissionInterruptClaim, registerChatThreadsShareable, retryQueuedSubmissionReceipt, resolveRunThreadScope, resolveThreadAccess, listThreads, searchThreads, renameThread, createThreadShareLink, getThreadByShareToken, getThreadShareState, revokeThreadShareLink, setThreadArchived, setThreadPinned, setThreadScope, updateThreadData, withThreadDataLock, deleteThread, mutateThreadQueuedMessages, setThreadSourceIfMissing, isAppOwnedChatScope, isChatThreadOwnership, threadScopeMismatch, } from "../chat-threads/store.js";
|
|
36
|
+
import { InlineAttachmentDataNotPersistableError, QueuedSubmissionAdmissionError, adoptThreadScopeIfUnscoped, blockQueuedSubmissionReceipt, clearQueuedSubmissionInterruptRun, createThread, forkThread, getThread, getQueuedSubmissionReceipt, getQueuedSubmissionReceiptStatus, listQueuedSubmissionReceipts, markQueuedSubmissionSubmitted, queuedSubmissionBehaviorMatches, recordQueuedSubmissionInterruptRun, renewQueuedSubmissionInterruptClaim, registerChatThreadsShareable, retryQueuedSubmissionReceipt, resolveRunThreadScope, resolveThreadAccess, resolveThreadAccessScope, listThreads, searchThreads, renameThread, createThreadShareLink, getThreadByShareToken, getThreadShareState, revokeThreadShareLink, setThreadArchived, setThreadPinned, setThreadScope, updateThreadData, withThreadDataLock, deleteThread, mutateThreadQueuedMessages, setThreadSourceIfMissing, isAppOwnedChatScope, isChatThreadOwnership, threadScopeMismatch, } from "../chat-threads/store.js";
|
|
37
37
|
import { isCheckpointRestorePath } from "../checkpoints/route-match.js";
|
|
38
38
|
import { createDbAdminAgentTools } from "../db-admin/agent-tools.js";
|
|
39
39
|
import { isTransientDatabaseError } from "../db/client.js";
|
|
@@ -78,10 +78,12 @@ import { loadHostedHarnessConfig } from "./hosted-harness-policy.js";
|
|
|
78
78
|
import { startIntervalJob } from "./interval-job.js";
|
|
79
79
|
import { isDirectLoopbackRequest } from "./loopback.js";
|
|
80
80
|
import { getModelFamilyOverlay } from "./prompts/index.js";
|
|
81
|
+
import { scheduleQueuedSubmissionInboxDrain } from "./queued-submission-inbox-drain.js";
|
|
81
82
|
import { mountRealtimeVoiceRoutes } from "./realtime-voice.js";
|
|
82
83
|
import { runWithRequestContext, getRequestContext, getRequestOrgId, getRequestUserEmail, getRequestRunContext, ensureRequestRunContext, } from "./request-context.js";
|
|
83
84
|
import { getForwardedRequestOrigin } from "./request-origin.js";
|
|
84
85
|
export { handleSharedThreadRequest };
|
|
86
|
+
const MAX_QUEUED_SUBMISSION_RETRIES = 5;
|
|
85
87
|
export function trackAgentChatRunLifecycle(event, threadId, attemptId, userId, properties = {}, appId, trackingSource) {
|
|
86
88
|
if (!threadId?.trim() ||
|
|
87
89
|
!attemptId?.trim() ||
|
|
@@ -298,6 +300,33 @@ export async function runPreAgentTurnAutosave(callback, scope, run) {
|
|
|
298
300
|
}
|
|
299
301
|
}
|
|
300
302
|
export { foldAgentChatRunCompletion };
|
|
303
|
+
export function assertAgentChatRunProjectionUpdated(updated, threadId, runId) {
|
|
304
|
+
if (!updated) {
|
|
305
|
+
throw new Error(`Agent chat thread ${threadId} could not save the projection for run ${runId}.`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
export async function runAgentChatRunCompletionHooksAfterProjection(persistProjection, runCompletionHooks) {
|
|
309
|
+
let projectionFailed = false;
|
|
310
|
+
let projectionError;
|
|
311
|
+
try {
|
|
312
|
+
await persistProjection();
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
projectionFailed = true;
|
|
316
|
+
projectionError = error;
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
await runCompletionHooks();
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
if (projectionFailed) {
|
|
323
|
+
throw new AggregateError([projectionError, error], "Agent chat projection and completion hooks failed.");
|
|
324
|
+
}
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
if (projectionFailed)
|
|
328
|
+
throw projectionError;
|
|
329
|
+
}
|
|
301
330
|
/**
|
|
302
331
|
* The model this mount runs with, when the caller does not pass one per request.
|
|
303
332
|
*
|
|
@@ -429,6 +458,7 @@ export async function runA2AAgentLoopWithRunManager(runOptions, pluginOptions, t
|
|
|
429
458
|
: undefined;
|
|
430
459
|
if (reasonCode === "stale_execution_fence" ||
|
|
431
460
|
reasonCode === A2A_TASK_CLAIM_LOST_ERROR_CODE) {
|
|
461
|
+
run.abortReason = "execution_lease_lost";
|
|
432
462
|
run.abort.abort("execution_lease_lost");
|
|
433
463
|
return;
|
|
434
464
|
}
|
|
@@ -2925,7 +2955,7 @@ export function createAgentChatPlugin(options) {
|
|
|
2925
2955
|
// the frontend-triggered saves below). Without the lock, a concurrent
|
|
2926
2956
|
// queued-message save can clobber the assistant message we just
|
|
2927
2957
|
// appended here, or vice versa.
|
|
2928
|
-
await withThreadDataLock(threadId, async () => {
|
|
2958
|
+
await runAgentChatRunCompletionHooksAfterProjection(() => withThreadDataLock(threadId, async () => {
|
|
2929
2959
|
const thread = await getThread(threadId);
|
|
2930
2960
|
if (!thread) {
|
|
2931
2961
|
throw new Error(`Agent chat thread ${threadId} was not found while saving run ${run.runId}.`);
|
|
@@ -2949,14 +2979,25 @@ export function createAgentChatPlugin(options) {
|
|
|
2949
2979
|
};
|
|
2950
2980
|
repo = appendThreadDebugHistory(repo, debug);
|
|
2951
2981
|
const meta = extractThreadMeta(repo);
|
|
2952
|
-
await updateThreadData(threadId, JSON.stringify(repo), thread.title, meta.preview || thread.preview, repo.messages.length, { trustedRunSequenceResetIds: new Set([run.runId]) });
|
|
2982
|
+
const projectionUpdated = await updateThreadData(threadId, JSON.stringify(repo), thread.title, meta.preview || thread.preview, repo.messages.length, { trustedRunSequenceResetIds: new Set([run.runId]) });
|
|
2983
|
+
assertAgentChatRunProjectionUpdated(projectionUpdated, threadId, run.runId);
|
|
2984
|
+
}), async () => {
|
|
2985
|
+
// Checkpoint creation is part of durable turn completion. The helper
|
|
2986
|
+
// catches and reports its own failures, so a broken app checkpoint does
|
|
2987
|
+
// not strand the run while a successful checkpoint cannot be lost when
|
|
2988
|
+
// a serverless invocation exits.
|
|
2989
|
+
await runPostAgentTurnAutosave(options?.onAgentTurnComplete, chatScope, run);
|
|
2990
|
+
await runPostAgentRunComplete(options?.onAgentRunComplete, chatScope, run, { turnContinues: endsAtContinuationBoundary(run) });
|
|
2991
|
+
});
|
|
2992
|
+
scheduleQueuedSubmissionInboxDrain({
|
|
2993
|
+
threadId: runThreadId,
|
|
2994
|
+
turnContinues: endsAtContinuationBoundary(run),
|
|
2995
|
+
waitUntil: getRequestRunContext()?.waitUntil,
|
|
2996
|
+
drain: drainQueuedSubmissionInbox,
|
|
2997
|
+
onError: (error) => {
|
|
2998
|
+
console.error(`[agent-chat] queued-submission follow-up drain failed for ${runThreadId}:`, error);
|
|
2999
|
+
},
|
|
2953
3000
|
});
|
|
2954
|
-
// Checkpoint creation is part of durable turn completion. The helper
|
|
2955
|
-
// catches and reports its own failures, so a broken app checkpoint does
|
|
2956
|
-
// not strand the run while a successful checkpoint cannot be lost when
|
|
2957
|
-
// a serverless invocation exits.
|
|
2958
|
-
await runPostAgentTurnAutosave(options?.onAgentTurnComplete, chatScope, run);
|
|
2959
|
-
await runPostAgentRunComplete(options?.onAgentRunComplete, chatScope, run, { turnContinues: endsAtContinuationBoundary(run) });
|
|
2960
3001
|
// Event triggers and local git checkpoints remain best effort and do
|
|
2961
3002
|
// not extend the durable chat persistence gate.
|
|
2962
3003
|
void (async () => {
|
|
@@ -5866,6 +5907,17 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
5866
5907
|
};
|
|
5867
5908
|
// ── Specific thread: GET/PUT/DELETE /threads/:id ──
|
|
5868
5909
|
if (threadId) {
|
|
5910
|
+
if (method === "GET" &&
|
|
5911
|
+
threadTail[0] === "queue" &&
|
|
5912
|
+
threadTail[1] &&
|
|
5913
|
+
threadTail[2] === "receipt" &&
|
|
5914
|
+
threadTail.length === 3) {
|
|
5915
|
+
const thread = await resolveThreadAccessScope(owner, threadId, "viewer", { orgId });
|
|
5916
|
+
if (!thread || !threadMatchesRequestedScope(thread)) {
|
|
5917
|
+
return threadNotFound();
|
|
5918
|
+
}
|
|
5919
|
+
return await getQueuedSubmissionReceiptStatus(threadId, threadTail[1]);
|
|
5920
|
+
}
|
|
5869
5921
|
if (method === "GET") {
|
|
5870
5922
|
const thread = await resolveThreadAccess(owner, threadId, "viewer", { orgId });
|
|
5871
5923
|
if (!thread || !threadMatchesRequestedScope(thread)) {
|
|
@@ -6129,7 +6181,9 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6129
6181
|
mutation = { type: "append", message: queued };
|
|
6130
6182
|
}
|
|
6131
6183
|
}
|
|
6132
|
-
else if ((record?.type === "remove" ||
|
|
6184
|
+
else if ((record?.type === "remove" ||
|
|
6185
|
+
record?.type === "cancel" ||
|
|
6186
|
+
record?.type === "moveToTop") &&
|
|
6133
6187
|
typeof record.messageId === "string" &&
|
|
6134
6188
|
record.messageId) {
|
|
6135
6189
|
mutation = {
|
|
@@ -6229,12 +6283,30 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6229
6283
|
retryable: true,
|
|
6230
6284
|
};
|
|
6231
6285
|
}
|
|
6286
|
+
if (mutation.type === "append" &&
|
|
6287
|
+
result.message &&
|
|
6288
|
+
!result.alreadySubmitted &&
|
|
6289
|
+
!result.submissionExpired) {
|
|
6290
|
+
scheduleQueuedSubmissionInboxDrain({
|
|
6291
|
+
threadId,
|
|
6292
|
+
turnContinues: false,
|
|
6293
|
+
waitUntil: getRequestRunContext()?.waitUntil,
|
|
6294
|
+
drain: drainQueuedSubmissionInbox,
|
|
6295
|
+
onError: (error) => {
|
|
6296
|
+
console.error(`[agent-chat] queued-submission append drain failed for ${threadId}:`, error);
|
|
6297
|
+
},
|
|
6298
|
+
});
|
|
6299
|
+
}
|
|
6300
|
+
if (mutation.type === "cancel" && result.submittedRunId) {
|
|
6301
|
+
await abortRunAndTurnDurably(result.submittedRunId, clientAbortReason("user"));
|
|
6302
|
+
}
|
|
6232
6303
|
const withoutClaim = (message) => {
|
|
6233
6304
|
const { promotionClaim: _claim, ...safeMessage } = message;
|
|
6234
6305
|
return safeMessage;
|
|
6235
6306
|
};
|
|
6307
|
+
const { submittedRunId: _submittedRunId, ...safeResult } = result;
|
|
6236
6308
|
return {
|
|
6237
|
-
...result,
|
|
6309
|
+
...(mutation.type === "cancel" ? safeResult : result),
|
|
6238
6310
|
queuedMessages: result.queuedMessages.map(withoutClaim),
|
|
6239
6311
|
...(result.message
|
|
6240
6312
|
? { message: withoutClaim(result.message) }
|
|
@@ -6407,6 +6479,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6407
6479
|
const scope = parseScopeFromQuery(query);
|
|
6408
6480
|
const unscopedOnly = String(query.unscoped ?? "") === "1";
|
|
6409
6481
|
const includeExternal = String(query.includeExternal ?? "") === "1";
|
|
6482
|
+
const includeArchived = String(query.includeArchived ?? "") === "1";
|
|
6410
6483
|
const ownership = query.ownership === undefined ? "all" : query.ownership;
|
|
6411
6484
|
if (!isChatThreadOwnership(ownership)) {
|
|
6412
6485
|
setResponseStatus(event, 400);
|
|
@@ -6420,6 +6493,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6420
6493
|
scope: scope ?? undefined,
|
|
6421
6494
|
orgId,
|
|
6422
6495
|
includeExternal,
|
|
6496
|
+
includeArchived,
|
|
6423
6497
|
sourceAppId: options?.appId ?? null,
|
|
6424
6498
|
ownership,
|
|
6425
6499
|
offset,
|
|
@@ -6431,6 +6505,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6431
6505
|
unscopedOnly,
|
|
6432
6506
|
orgId,
|
|
6433
6507
|
includeExternal,
|
|
6508
|
+
includeArchived,
|
|
6434
6509
|
sourceAppId: options?.appId ?? null,
|
|
6435
6510
|
ownership,
|
|
6436
6511
|
});
|
|
@@ -6563,7 +6638,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6563
6638
|
return handler(event);
|
|
6564
6639
|
});
|
|
6565
6640
|
};
|
|
6566
|
-
const drainQueuedSubmissionInbox = async () => {
|
|
6641
|
+
const drainQueuedSubmissionInbox = async (drainOptions = {}) => {
|
|
6567
6642
|
const result = {
|
|
6568
6643
|
scanned: 0,
|
|
6569
6644
|
claimed: 0,
|
|
@@ -6573,8 +6648,16 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6573
6648
|
expired: 0,
|
|
6574
6649
|
failed: 0,
|
|
6575
6650
|
};
|
|
6576
|
-
const pending = await listQueuedSubmissionReceipts({
|
|
6651
|
+
const pending = await listQueuedSubmissionReceipts({
|
|
6652
|
+
limit: 25,
|
|
6653
|
+
...(drainOptions.threadId ? { threadId: drainOptions.threadId } : {}),
|
|
6654
|
+
});
|
|
6577
6655
|
result.scanned = pending.length;
|
|
6656
|
+
const deferredThreads = new Set();
|
|
6657
|
+
const deferReceipt = (threadId) => {
|
|
6658
|
+
result.deferred += 1;
|
|
6659
|
+
deferredThreads.add(threadId);
|
|
6660
|
+
};
|
|
6578
6661
|
const deadlineAt = Date.now() + 30_000;
|
|
6579
6662
|
const maxAdmissions = 5;
|
|
6580
6663
|
const waitForStableIdle = async (threadId) => {
|
|
@@ -6596,10 +6679,75 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6596
6679
|
return false;
|
|
6597
6680
|
};
|
|
6598
6681
|
for (const receipt of pending) {
|
|
6682
|
+
if (deferredThreads.has(receipt.threadId)) {
|
|
6683
|
+
result.deferred += 1;
|
|
6684
|
+
continue;
|
|
6685
|
+
}
|
|
6599
6686
|
if (Date.now() >= deadlineAt || result.submitted >= maxAdmissions) {
|
|
6600
6687
|
break;
|
|
6601
6688
|
}
|
|
6689
|
+
if (drainOptions.threadId &&
|
|
6690
|
+
!(await waitForStableIdle(drainOptions.threadId))) {
|
|
6691
|
+
deferReceipt(receipt.threadId);
|
|
6692
|
+
break;
|
|
6693
|
+
}
|
|
6602
6694
|
let claimId;
|
|
6695
|
+
let retryCount = receipt.retryCount;
|
|
6696
|
+
let recoveryMutationAttempted = false;
|
|
6697
|
+
const retryClaimedReceipt = async (countRetry = false) => {
|
|
6698
|
+
if (!claimId) {
|
|
6699
|
+
throw new Error(`Queued submission ${receipt.messageId} has no active claim to retry`);
|
|
6700
|
+
}
|
|
6701
|
+
recoveryMutationAttempted = true;
|
|
6702
|
+
let updated = await retryQueuedSubmissionReceipt(receipt.threadId, receipt.messageId, Date.now() + 10_000, { claimId, ...(countRetry ? { countRetry: true } : {}) });
|
|
6703
|
+
if (!updated) {
|
|
6704
|
+
updated = await retryQueuedSubmissionReceipt(receipt.threadId, receipt.messageId, Date.now() + 10_000, countRetry ? { countRetry: true } : {});
|
|
6705
|
+
}
|
|
6706
|
+
if (updated && countRetry)
|
|
6707
|
+
retryCount += 1;
|
|
6708
|
+
return updated;
|
|
6709
|
+
};
|
|
6710
|
+
const blockClaimedReceipt = async () => {
|
|
6711
|
+
if (!claimId) {
|
|
6712
|
+
throw new Error(`Queued submission ${receipt.messageId} has no active claim to block`);
|
|
6713
|
+
}
|
|
6714
|
+
recoveryMutationAttempted = true;
|
|
6715
|
+
const updated = await blockQueuedSubmissionReceipt(receipt.threadId, receipt.messageId, {
|
|
6716
|
+
claimId,
|
|
6717
|
+
});
|
|
6718
|
+
return (updated ||
|
|
6719
|
+
(await blockQueuedSubmissionReceipt(receipt.threadId, receipt.messageId)));
|
|
6720
|
+
};
|
|
6721
|
+
const recoverClaimedReceipt = async () => {
|
|
6722
|
+
if (!claimId) {
|
|
6723
|
+
deferReceipt(receipt.threadId);
|
|
6724
|
+
return;
|
|
6725
|
+
}
|
|
6726
|
+
if (!recoveryMutationAttempted &&
|
|
6727
|
+
retryCount >= MAX_QUEUED_SUBMISSION_RETRIES) {
|
|
6728
|
+
const blocked = await blockClaimedReceipt();
|
|
6729
|
+
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
6730
|
+
type: "release",
|
|
6731
|
+
messageId: receipt.messageId,
|
|
6732
|
+
claimId,
|
|
6733
|
+
});
|
|
6734
|
+
claimId = undefined;
|
|
6735
|
+
if (blocked)
|
|
6736
|
+
result.blocked += 1;
|
|
6737
|
+
else
|
|
6738
|
+
deferReceipt(receipt.threadId);
|
|
6739
|
+
return;
|
|
6740
|
+
}
|
|
6741
|
+
if (!recoveryMutationAttempted)
|
|
6742
|
+
await retryClaimedReceipt(true);
|
|
6743
|
+
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
6744
|
+
type: "release",
|
|
6745
|
+
messageId: receipt.messageId,
|
|
6746
|
+
claimId,
|
|
6747
|
+
});
|
|
6748
|
+
claimId = undefined;
|
|
6749
|
+
deferReceipt(receipt.threadId);
|
|
6750
|
+
};
|
|
6603
6751
|
try {
|
|
6604
6752
|
const message = receipt.message;
|
|
6605
6753
|
if (!message ||
|
|
@@ -6610,7 +6758,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6610
6758
|
if (blocked)
|
|
6611
6759
|
result.blocked += 1;
|
|
6612
6760
|
else
|
|
6613
|
-
|
|
6761
|
+
deferReceipt(receipt.threadId);
|
|
6614
6762
|
continue;
|
|
6615
6763
|
}
|
|
6616
6764
|
const thread = await resolveThreadAccess(receipt.actor.email, receipt.threadId, "editor", { orgId: receipt.actor.orgId ?? undefined });
|
|
@@ -6619,7 +6767,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6619
6767
|
if (blocked)
|
|
6620
6768
|
result.blocked += 1;
|
|
6621
6769
|
else
|
|
6622
|
-
|
|
6770
|
+
deferReceipt(receipt.threadId);
|
|
6623
6771
|
continue;
|
|
6624
6772
|
}
|
|
6625
6773
|
claimId = crypto.randomUUID();
|
|
@@ -6635,14 +6783,18 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6635
6783
|
if (error instanceof QueuedSubmissionAdmissionError &&
|
|
6636
6784
|
error.code !== "queued_message_id_conflict") {
|
|
6637
6785
|
claimId = undefined;
|
|
6638
|
-
|
|
6786
|
+
deferReceipt(receipt.threadId);
|
|
6639
6787
|
continue;
|
|
6640
6788
|
}
|
|
6641
6789
|
throw error;
|
|
6642
6790
|
}
|
|
6643
6791
|
if (claim?.receiptUnavailable) {
|
|
6644
6792
|
claimId = undefined;
|
|
6645
|
-
|
|
6793
|
+
deferReceipt(receipt.threadId);
|
|
6794
|
+
continue;
|
|
6795
|
+
}
|
|
6796
|
+
if (claim?.retryDeferred) {
|
|
6797
|
+
deferReceipt(receipt.threadId);
|
|
6646
6798
|
continue;
|
|
6647
6799
|
}
|
|
6648
6800
|
if (claim?.receiptConflict) {
|
|
@@ -6651,7 +6803,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6651
6803
|
continue;
|
|
6652
6804
|
}
|
|
6653
6805
|
if (claim?.claimBusy) {
|
|
6654
|
-
|
|
6806
|
+
deferReceipt(receipt.threadId);
|
|
6655
6807
|
continue;
|
|
6656
6808
|
}
|
|
6657
6809
|
if (claim?.submissionExpired) {
|
|
@@ -6663,7 +6815,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6663
6815
|
if (blocked)
|
|
6664
6816
|
result.blocked += 1;
|
|
6665
6817
|
else
|
|
6666
|
-
|
|
6818
|
+
deferReceipt(receipt.threadId);
|
|
6667
6819
|
continue;
|
|
6668
6820
|
}
|
|
6669
6821
|
const claimedMessage = claim.claimedMessage;
|
|
@@ -6674,7 +6826,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6674
6826
|
result.submitted += 1;
|
|
6675
6827
|
}
|
|
6676
6828
|
else {
|
|
6677
|
-
|
|
6829
|
+
deferReceipt(receipt.threadId);
|
|
6678
6830
|
}
|
|
6679
6831
|
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
6680
6832
|
type: "release",
|
|
@@ -6684,6 +6836,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6684
6836
|
claimId = undefined;
|
|
6685
6837
|
continue;
|
|
6686
6838
|
}
|
|
6839
|
+
retryCount = claimedReceipt.retryCount;
|
|
6687
6840
|
const finishInterrupt = async (runId) => {
|
|
6688
6841
|
if (!(await renewQueuedSubmissionInterruptClaim({
|
|
6689
6842
|
threadId: receipt.threadId,
|
|
@@ -6718,28 +6871,28 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6718
6871
|
if (claimedReceipt.interruptRunId) {
|
|
6719
6872
|
const stableIdle = await finishInterrupt(claimedReceipt.interruptRunId);
|
|
6720
6873
|
if (!stableIdle) {
|
|
6721
|
-
await
|
|
6874
|
+
await retryClaimedReceipt();
|
|
6722
6875
|
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
6723
6876
|
type: "release",
|
|
6724
6877
|
messageId: receipt.messageId,
|
|
6725
6878
|
claimId,
|
|
6726
6879
|
});
|
|
6727
6880
|
claimId = undefined;
|
|
6728
|
-
|
|
6881
|
+
deferReceipt(receipt.threadId);
|
|
6729
6882
|
continue;
|
|
6730
6883
|
}
|
|
6731
6884
|
}
|
|
6732
6885
|
const active = await getActiveRunForThreadAsync(receipt.threadId);
|
|
6733
6886
|
if (active?.inFlight) {
|
|
6734
6887
|
if (claimedMessage.interruptActiveRun !== true) {
|
|
6735
|
-
await
|
|
6888
|
+
await retryClaimedReceipt();
|
|
6736
6889
|
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
6737
6890
|
type: "release",
|
|
6738
6891
|
messageId: receipt.messageId,
|
|
6739
6892
|
claimId,
|
|
6740
6893
|
});
|
|
6741
6894
|
claimId = undefined;
|
|
6742
|
-
|
|
6895
|
+
deferReceipt(receipt.threadId);
|
|
6743
6896
|
continue;
|
|
6744
6897
|
}
|
|
6745
6898
|
const recorded = await recordQueuedSubmissionInterruptRun({
|
|
@@ -6749,25 +6902,25 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6749
6902
|
claimId,
|
|
6750
6903
|
});
|
|
6751
6904
|
if (!recorded) {
|
|
6752
|
-
await
|
|
6905
|
+
await retryClaimedReceipt();
|
|
6753
6906
|
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
6754
6907
|
type: "release",
|
|
6755
6908
|
messageId: receipt.messageId,
|
|
6756
6909
|
claimId,
|
|
6757
6910
|
});
|
|
6758
6911
|
claimId = undefined;
|
|
6759
|
-
|
|
6912
|
+
deferReceipt(receipt.threadId);
|
|
6760
6913
|
continue;
|
|
6761
6914
|
}
|
|
6762
6915
|
if (!(await finishInterrupt(active.runId))) {
|
|
6763
|
-
await
|
|
6916
|
+
await retryClaimedReceipt();
|
|
6764
6917
|
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
6765
6918
|
type: "release",
|
|
6766
6919
|
messageId: receipt.messageId,
|
|
6767
6920
|
claimId,
|
|
6768
6921
|
});
|
|
6769
6922
|
claimId = undefined;
|
|
6770
|
-
|
|
6923
|
+
deferReceipt(receipt.threadId);
|
|
6771
6924
|
continue;
|
|
6772
6925
|
}
|
|
6773
6926
|
}
|
|
@@ -6788,6 +6941,9 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6788
6941
|
...(claimedMessage.requestAttachments !== undefined
|
|
6789
6942
|
? { requestAttachments: claimedMessage.requestAttachments }
|
|
6790
6943
|
: {}),
|
|
6944
|
+
...(claimedMessage.references !== undefined
|
|
6945
|
+
? { references: claimedMessage.references }
|
|
6946
|
+
: {}),
|
|
6791
6947
|
...(claimedMessage.metadata !== undefined
|
|
6792
6948
|
? { metadata: claimedMessage.metadata }
|
|
6793
6949
|
: {}),
|
|
@@ -6813,6 +6969,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6813
6969
|
orgId: receipt.actor.orgId ?? null,
|
|
6814
6970
|
orgScope: receipt.actor.orgScope ?? null,
|
|
6815
6971
|
};
|
|
6972
|
+
seedAgentRunOwnerContext(admissionEvent, ownerContext);
|
|
6816
6973
|
let admissionResponse;
|
|
6817
6974
|
try {
|
|
6818
6975
|
admissionResponse = await runWithAgentRunContext({
|
|
@@ -6827,9 +6984,9 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6827
6984
|
afterError = await getQueuedSubmissionReceipt(receipt.threadId, receipt.messageId);
|
|
6828
6985
|
}
|
|
6829
6986
|
catch (receiptError) {
|
|
6830
|
-
result.failed += 1;
|
|
6831
6987
|
console.error(`[agent-chat] could not verify queued submission ${receipt.messageId} after admission failed:`, { error, receiptError });
|
|
6832
|
-
|
|
6988
|
+
await recoverClaimedReceipt();
|
|
6989
|
+
result.failed += 1;
|
|
6833
6990
|
continue;
|
|
6834
6991
|
}
|
|
6835
6992
|
if (afterError?.state === "submitted") {
|
|
@@ -6837,14 +6994,34 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6837
6994
|
claimId = undefined;
|
|
6838
6995
|
continue;
|
|
6839
6996
|
}
|
|
6840
|
-
|
|
6997
|
+
const nonRetryableError = error !== null &&
|
|
6998
|
+
typeof error === "object" &&
|
|
6999
|
+
"retryable" in error &&
|
|
7000
|
+
error.retryable === false;
|
|
7001
|
+
const retryLimitReached = (afterError?.retryCount ?? 0) >= MAX_QUEUED_SUBMISSION_RETRIES;
|
|
7002
|
+
if (nonRetryableError || retryLimitReached) {
|
|
7003
|
+
const blocked = await blockClaimedReceipt();
|
|
7004
|
+
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
7005
|
+
type: "release",
|
|
7006
|
+
messageId: receipt.messageId,
|
|
7007
|
+
claimId,
|
|
7008
|
+
});
|
|
7009
|
+
claimId = undefined;
|
|
7010
|
+
if (blocked)
|
|
7011
|
+
result.blocked += 1;
|
|
7012
|
+
else
|
|
7013
|
+
deferReceipt(receipt.threadId);
|
|
7014
|
+
console.error(`[agent-chat] queued submission admission could not be retried for ${receipt.messageId}:`, error);
|
|
7015
|
+
continue;
|
|
7016
|
+
}
|
|
7017
|
+
await retryClaimedReceipt(true);
|
|
6841
7018
|
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
6842
7019
|
type: "release",
|
|
6843
7020
|
messageId: receipt.messageId,
|
|
6844
7021
|
claimId,
|
|
6845
7022
|
});
|
|
6846
7023
|
claimId = undefined;
|
|
6847
|
-
|
|
7024
|
+
deferReceipt(receipt.threadId);
|
|
6848
7025
|
console.error(`[agent-chat] queued submission admission failed for ${receipt.messageId}:`, error);
|
|
6849
7026
|
continue;
|
|
6850
7027
|
}
|
|
@@ -6869,18 +7046,18 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6869
7046
|
admittedReceipt = await getQueuedSubmissionReceipt(receipt.threadId, receipt.messageId);
|
|
6870
7047
|
}
|
|
6871
7048
|
catch (error) {
|
|
6872
|
-
result.failed += 1;
|
|
6873
7049
|
console.error(`[agent-chat] could not verify queued submission ${receipt.messageId} after admission returned:`, error);
|
|
6874
|
-
claimId = undefined;
|
|
6875
7050
|
await stream
|
|
6876
7051
|
?.cancel()
|
|
6877
7052
|
.catch((cancelError) => console.error(`[agent-chat] could not cancel stream for unverified queued submission ${receipt.messageId}:`, cancelError));
|
|
7053
|
+
await recoverClaimedReceipt();
|
|
7054
|
+
result.failed += 1;
|
|
6878
7055
|
continue;
|
|
6879
7056
|
}
|
|
6880
7057
|
if (responseRunId &&
|
|
6881
7058
|
(responseStatus < 400 || admittedReceipt?.state === "submitted")) {
|
|
6882
7059
|
if (admittedReceipt?.state !== "submitted") {
|
|
6883
|
-
await
|
|
7060
|
+
await blockClaimedReceipt();
|
|
6884
7061
|
result.failed += 1;
|
|
6885
7062
|
console.error(`[agent-chat] run ${responseRunId} started without a submitted receipt for ${receipt.messageId}`);
|
|
6886
7063
|
}
|
|
@@ -6897,21 +7074,38 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6897
7074
|
await stream?.cancel().catch(() => { });
|
|
6898
7075
|
continue;
|
|
6899
7076
|
}
|
|
6900
|
-
if (
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
7077
|
+
if (responseCode === "run_slot_busy") {
|
|
7078
|
+
// The thread's run slot is still held by a run that is ending. That
|
|
7079
|
+
// is a wait, not a failed admission: release the claim without
|
|
7080
|
+
// spending a retry or setting a backoff, so the completion drain
|
|
7081
|
+
// for that run can claim this receipt. A backoff here would make
|
|
7082
|
+
// that drain skip it until the recurring sweep.
|
|
7083
|
+
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
7084
|
+
type: "release",
|
|
7085
|
+
messageId: receipt.messageId,
|
|
7086
|
+
claimId,
|
|
7087
|
+
});
|
|
7088
|
+
claimId = undefined;
|
|
7089
|
+
deferReceipt(receipt.threadId);
|
|
7090
|
+
await stream?.cancel().catch(() => { });
|
|
7091
|
+
continue;
|
|
7092
|
+
}
|
|
7093
|
+
const retryableAdmission = responseBody?.retryable === true ||
|
|
7094
|
+
(responseBody?.retryable !== false && responseStatus >= 500);
|
|
7095
|
+
if (retryableAdmission &&
|
|
7096
|
+
retryCount < MAX_QUEUED_SUBMISSION_RETRIES) {
|
|
7097
|
+
await retryClaimedReceipt(true);
|
|
6904
7098
|
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
6905
7099
|
type: "release",
|
|
6906
7100
|
messageId: receipt.messageId,
|
|
6907
7101
|
claimId,
|
|
6908
7102
|
});
|
|
6909
7103
|
claimId = undefined;
|
|
6910
|
-
|
|
7104
|
+
deferReceipt(receipt.threadId);
|
|
6911
7105
|
await stream?.cancel().catch(() => { });
|
|
6912
7106
|
continue;
|
|
6913
7107
|
}
|
|
6914
|
-
const blocked = await
|
|
7108
|
+
const blocked = await blockClaimedReceipt();
|
|
6915
7109
|
await mutateThreadQueuedMessages(receipt.threadId, {
|
|
6916
7110
|
type: "release",
|
|
6917
7111
|
messageId: receipt.messageId,
|
|
@@ -6921,24 +7115,18 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6921
7115
|
if (blocked)
|
|
6922
7116
|
result.blocked += 1;
|
|
6923
7117
|
else
|
|
6924
|
-
|
|
7118
|
+
deferReceipt(receipt.threadId);
|
|
6925
7119
|
await stream?.cancel().catch(() => { });
|
|
6926
7120
|
}
|
|
6927
7121
|
catch (error) {
|
|
6928
7122
|
result.failed += 1;
|
|
6929
7123
|
console.error(`[agent-chat] queued submission drain failed for ${receipt.messageId}:`, error);
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
claimId,
|
|
6937
|
-
});
|
|
6938
|
-
}
|
|
6939
|
-
catch (releaseError) {
|
|
6940
|
-
console.error(`[agent-chat] could not release queued submission ${receipt.messageId}:`, releaseError);
|
|
6941
|
-
}
|
|
7124
|
+
try {
|
|
7125
|
+
await recoverClaimedReceipt();
|
|
7126
|
+
}
|
|
7127
|
+
catch (releaseError) {
|
|
7128
|
+
console.error(`[agent-chat] could not release queued submission ${receipt.messageId}:`, releaseError);
|
|
7129
|
+
deferReceipt(receipt.threadId);
|
|
6942
7130
|
}
|
|
6943
7131
|
}
|
|
6944
7132
|
}
|
|
@@ -16,9 +16,9 @@ export declare function createAgentEngineDisconnectHandler(): import("h3").Event
|
|
|
16
16
|
error: any;
|
|
17
17
|
scope?: undefined;
|
|
18
18
|
} | {
|
|
19
|
-
error?: undefined;
|
|
20
19
|
ok: boolean;
|
|
21
20
|
scope: "org" | "user";
|
|
21
|
+
error?: undefined;
|
|
22
22
|
}>>;
|
|
23
23
|
export interface DefaultModelSelectionRequest {
|
|
24
24
|
engine: string;
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
* acquisition; last touch answers "what brought them to sign up?" and credits
|
|
14
14
|
* the post, video, or person that converted them.
|
|
15
15
|
*
|
|
16
|
+
* First touch also has a durable copy, `an_fts`, that our server sets for a
|
|
17
|
+
* year (see `first-touch-route.ts`). Signup reads both first-touch cookies and
|
|
18
|
+
* keeps the one `preferFirstTouch` picks.
|
|
19
|
+
*
|
|
16
20
|
* This module is intentionally pure and dependency-free so it is trivially
|
|
17
21
|
* unit-testable and can never throw into the signup path. The single hard rule:
|
|
18
22
|
* parsing untrusted cookie input must NEVER throw — every accessor is defensive.
|
|
@@ -80,11 +84,21 @@ export declare const LAST_TOUCH_COOKIE_NAME = "an_lt";
|
|
|
80
84
|
export declare function parseCookieHeader(cookieHeader: string | null | undefined): Record<string, string>;
|
|
81
85
|
export declare function decodeFirstTouchValue(value: string | null | undefined): FirstTouchAttribution | null;
|
|
82
86
|
export declare function decodeLastTouchValue(value: string | null | undefined): LastTouchAttribution | null;
|
|
87
|
+
/**
|
|
88
|
+
* Decode the year-long `an_fts` cookie. A value from another format version
|
|
89
|
+
* is unreadable here, so it holds no touch.
|
|
90
|
+
*/
|
|
91
|
+
export declare function decodeFirstTouchServerValue(value: string | null | undefined): FirstTouchAttribution | null;
|
|
83
92
|
/**
|
|
84
93
|
* Read the `an_ft` first-touch attribution out of a raw `Cookie:` header.
|
|
85
94
|
* Returns `null` when the cookie is absent or unparseable. Never throws.
|
|
86
95
|
*/
|
|
87
96
|
export declare function readFirstTouchAttribution(cookieHeader: string | null | undefined): FirstTouchAttribution | null;
|
|
97
|
+
/**
|
|
98
|
+
* The `an_fts` cookie value for a first touch, dropping the lowest-priority
|
|
99
|
+
* fields until `name=value` fits its budget.
|
|
100
|
+
*/
|
|
101
|
+
export declare function encodeFirstTouchServerCookieValue(touch: FirstTouchAttribution): string;
|
|
88
102
|
/**
|
|
89
103
|
* Read the `an_lt` last-touch attribution out of a raw `Cookie:` header.
|
|
90
104
|
* Returns `null` when the cookie is absent or unparseable. Never throws.
|