@agent-native/core 0.157.8 → 0.157.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/actions/purge-first-party-analytics-postgres.ts +26 -8
- package/corpus/templates/analytics/scripts/first-party-analytics-postgres-retention-dry-run.sql +261 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +3 -1
- package/corpus/templates/analytics/server/lib/first-party-analytics-purge.ts +75 -31
- package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +4 -1
- package/corpus/templates/analytics/server/plugins/db.ts +139 -0
- package/corpus/templates/slides/AGENTS.md +14 -10
- package/corpus/templates/slides/actions/export-pptx.ts +1311 -121
- package/corpus/templates/slides/actions/import-file.ts +28 -1
- package/corpus/templates/slides/actions/import-pptx.ts +69 -42
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +222 -29
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +71 -0
- package/corpus/templates/slides/app/global.css +19 -1
- package/corpus/templates/slides/app/lib/export-google-slides-client.ts +44 -5
- package/corpus/templates/slides/app/lib/export-pdf-client.ts +13 -6
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +601 -30
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +18 -1
- package/corpus/templates/slides/server/handlers/import/html-converter.ts +1240 -22
- package/corpus/templates/slides/server/handlers/import/pdf-fidelity-parser.ts +329 -64
- package/corpus/templates/slides/server/handlers/import/pptx-assets.ts +24 -0
- package/corpus/templates/slides/server/lib/source-import.ts +10 -1
- package/corpus/templates/slides/shared/aspect-ratios.ts +13 -1
- package/dist/agent/harness/migrations.d.ts +4 -0
- package/dist/agent/harness/migrations.js +60 -0
- package/dist/agent/production-agent.d.ts +2 -0
- package/dist/agent/production-agent.js +15 -0
- package/dist/agent/run-loop-with-resume.d.ts +1 -0
- package/dist/agent/run-loop-with-resume.js +44 -12
- package/dist/agent/run-migrations.d.ts +8 -0
- package/dist/agent/run-migrations.js +61 -0
- package/dist/automations/service.d.ts +6 -0
- package/dist/automations/service.js +35 -0
- package/dist/chat-threads/migrations.d.ts +1 -0
- package/dist/chat-threads/migrations.js +1 -0
- package/dist/chat-threads/schema-migrations.d.ts +8 -0
- package/dist/chat-threads/schema-migrations.js +60 -0
- package/dist/cli/code-agent-connector.d.ts +4 -1
- package/dist/cli/code-agent-connector.js +154 -23
- package/dist/cli/code-agent-executor.js +255 -13
- package/dist/cli/code-agent-runs.d.ts +1 -0
- package/dist/cli/code-agent-runs.js +2 -1
- package/dist/cli/portal-workspace.d.ts +49 -0
- package/dist/cli/portal-workspace.js +320 -0
- package/dist/client/AssistantChat.d.ts +1 -1
- package/dist/client/AssistantChat.js +43 -61
- package/dist/client/ConnectBuilderCard.js +33 -5
- package/dist/client/agent-chat-adapter.js +4 -0
- package/dist/client/analytics-platform.d.ts +2 -0
- package/dist/client/analytics-platform.js +12 -0
- package/dist/client/analytics.d.ts +3 -0
- package/dist/client/analytics.js +10 -1
- package/dist/client/chat/index.d.ts +1 -0
- package/dist/client/chat/index.js +1 -0
- package/dist/client/chat/message-components.d.ts +2 -0
- package/dist/client/chat/message-components.js +11 -1
- package/dist/client/chat/run-recovery.d.ts +2 -1
- package/dist/client/chat/run-recovery.js +2 -2
- package/dist/client/chat-first/apps-rail.d.ts +1 -1
- package/dist/client/chat-first/apps-rail.js +11 -11
- package/dist/client/chat-first/surface-tabs.d.ts +1 -1
- package/dist/client/chat-first/surface-tabs.js +38 -36
- package/dist/client/chat-first/types.d.ts +5 -0
- package/dist/client/chat-first.d.ts +1 -1
- package/dist/client/chat-first.js +4 -4
- package/dist/client/desktop-local-code-change.d.ts +10 -0
- package/dist/client/desktop-local-code-change.js +16 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +1 -0
- package/dist/client/observability/ThumbsFeedback.js +53 -26
- package/dist/client/observability/useObservability.d.ts +1 -1
- package/dist/client/observability/useObservability.js +6 -3
- package/dist/client/terminal/AgentTerminal.d.ts +9 -1
- package/dist/client/terminal/AgentTerminal.js +38 -3
- package/dist/client/terminal/index.d.ts +1 -1
- package/dist/client/terminal/index.js +1 -1
- package/dist/client/track.js +9 -1
- package/dist/client/use-action.js +3 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/deploy/build.js +1 -1
- package/dist/feature-flags/a2a-action-route.js +4 -2
- package/dist/feature-flags/permissions.d.ts +2 -0
- package/dist/feature-flags/permissions.js +6 -1
- package/dist/ingestion/pptx.d.ts +92 -1
- package/dist/ingestion/pptx.js +1180 -115
- package/dist/integrations/index.d.ts +3 -3
- package/dist/integrations/index.js +2 -2
- package/dist/integrations/plugin.js +95 -6
- package/dist/integrations/remote-commands-store.d.ts +5 -0
- package/dist/integrations/remote-commands-store.js +63 -22
- package/dist/integrations/remote-devices-store.d.ts +2 -1
- package/dist/integrations/remote-devices-store.js +46 -0
- package/dist/integrations/remote-types.d.ts +20 -0
- package/dist/jobs/actions/list-recurring-jobs.d.ts +3 -0
- package/dist/jobs/actions/list-recurring-jobs.js +5 -1
- package/dist/jobs/frontmatter.d.ts +16 -0
- package/dist/jobs/frontmatter.js +53 -0
- package/dist/jobs/remote-execution.d.ts +42 -0
- package/dist/jobs/remote-execution.js +287 -0
- package/dist/jobs/scheduler.js +102 -3
- package/dist/jobs/tools.js +50 -3
- package/dist/localization/core-messages/ar-SA.js +4 -0
- package/dist/localization/core-messages/de-DE.js +4 -0
- package/dist/localization/core-messages/en-US.d.ts +4 -0
- package/dist/localization/core-messages/en-US.js +4 -0
- package/dist/localization/core-messages/es-ES.js +4 -0
- package/dist/localization/core-messages/fr-FR.js +4 -0
- package/dist/localization/core-messages/hi-IN.js +4 -0
- package/dist/localization/core-messages/ja-JP.js +4 -0
- package/dist/localization/core-messages/ko-KR.js +4 -0
- package/dist/localization/core-messages/pt-BR.js +4 -0
- package/dist/localization/core-messages/zh-CN.js +4 -0
- package/dist/localization/core-messages/zh-TW.js +4 -0
- package/dist/localization/core-messages.d.ts +4 -0
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/feedback.js +40 -16
- package/dist/observability/routes.d.ts +6 -6
- package/dist/observability/routes.js +15 -3
- package/dist/observability/store.js +2 -0
- package/dist/observability/traces.js +5 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
- package/dist/provider-api/actions/provider-api.d.ts +13 -13
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/action-routes.d.ts +7 -5
- package/dist/server/action-routes.js +13 -6
- package/dist/server/agent-chat-plugin.js +6 -0
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-run-context.d.ts +1 -0
- package/dist/server/agent-run-context.js +9 -0
- package/dist/server/better-auth-instance.js +4 -0
- package/dist/server/core-routes-plugin.js +8 -1
- package/dist/server/realtime-voice.js +2 -1
- package/dist/server/release-migrations.js +16 -0
- package/dist/server/request-context.d.ts +2 -0
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/analytics-platform.d.ts +6 -0
- package/dist/shared/analytics-platform.js +14 -0
- package/dist/shared/mcp-embed-headers.d.ts +1 -1
- package/dist/shared/mcp-embed-headers.js +1 -1
- package/dist/styles/agent-native.css +83 -103
- package/dist/terminal/cli-registry.js +5 -0
- package/dist/tracking/registry.js +9 -1
- package/dist/triggers/actions/list-automations.d.ts +3 -0
- package/dist/triggers/actions/list-automations.js +3 -0
- package/dist/triggers/actions/manage-automation.d.ts +9 -0
- package/dist/triggers/actions/manage-automation.js +14 -2
- package/dist/triggers/actions.js +82 -7
- package/dist/usage/migrations.d.ts +4 -0
- package/dist/usage/migrations.js +45 -0
- package/docs/content/template-content-developers.mdx +48 -0
- package/docs/content/toolkit-ui.mdx +57 -0
- package/package.json +3 -3
|
@@ -263,10 +263,14 @@ const messages = {
|
|
|
263
263
|
"errorMessages.startNewChat": "새 채팅 시작",
|
|
264
264
|
"errorMessages.upgradeAtBuilder": "Builder.io에서 업그레이드",
|
|
265
265
|
"feedback.inaccurate": "부정확함",
|
|
266
|
+
"feedback.keyboardHint": "보내려면 {{shortcut}} Enter",
|
|
266
267
|
"feedback.notHelpful": "도움이 되지 않음",
|
|
268
|
+
"feedback.placeholder": "무엇이 문제였는지 알려주세요…",
|
|
269
|
+
"feedback.submit": "제출",
|
|
267
270
|
"feedback.thumbsDown": "싫어요",
|
|
268
271
|
"feedback.thumbsUp": "좋아요",
|
|
269
272
|
"feedback.tooSlow": "너무 느림",
|
|
273
|
+
"feedback.whatWentWrong": "무엇이 잘못되었나요?",
|
|
270
274
|
"feedback.wrongTool": "잘못된 도구",
|
|
271
275
|
"header.switchToCli": "CLI로 전환",
|
|
272
276
|
"history.active": "활성",
|
|
@@ -408,10 +408,14 @@ const messages = {
|
|
|
408
408
|
"errorMessages.startNewChat": "Iniciar novo chat",
|
|
409
409
|
"errorMessages.upgradeAtBuilder": "Fazer upgrade no Builder.io",
|
|
410
410
|
"feedback.inaccurate": "Impreciso",
|
|
411
|
+
"feedback.keyboardHint": "{{shortcut}} Enter para enviar",
|
|
411
412
|
"feedback.notHelpful": "Pouco útil",
|
|
413
|
+
"feedback.placeholder": "Conte-nos o que deu errado...",
|
|
414
|
+
"feedback.submit": "Enviar",
|
|
412
415
|
"feedback.thumbsDown": "Não gostei",
|
|
413
416
|
"feedback.thumbsUp": "Gostei",
|
|
414
417
|
"feedback.tooSlow": "Muito lento",
|
|
418
|
+
"feedback.whatWentWrong": "O que deu errado?",
|
|
415
419
|
"feedback.wrongTool": "Ferramenta errada",
|
|
416
420
|
"contextMeter.ariaLabel": "Contexto {{percent}}%, {{totalTokens}}{{breakdown}}. Abrir a análise de contexto.",
|
|
417
421
|
"contextMeter.breakdown": " no total: {{systemTokens}} do sistema + {{conversationTokens}} da conversa",
|
|
@@ -263,10 +263,14 @@ const messages = {
|
|
|
263
263
|
"errorMessages.startNewChat": "开始新聊天",
|
|
264
264
|
"errorMessages.upgradeAtBuilder": "在 Builder.io 升级",
|
|
265
265
|
"feedback.inaccurate": "不准确",
|
|
266
|
+
"feedback.keyboardHint": "{{shortcut}} Enter 发送",
|
|
266
267
|
"feedback.notHelpful": "没有帮助",
|
|
268
|
+
"feedback.placeholder": "告诉我们哪里出了问题……",
|
|
269
|
+
"feedback.submit": "提交",
|
|
267
270
|
"feedback.thumbsDown": "不喜欢",
|
|
268
271
|
"feedback.thumbsUp": "喜欢",
|
|
269
272
|
"feedback.tooSlow": "太慢",
|
|
273
|
+
"feedback.whatWentWrong": "哪里出了问题?",
|
|
270
274
|
"feedback.wrongTool": "工具错误",
|
|
271
275
|
"header.switchToCli": "切换到 CLI",
|
|
272
276
|
"history.active": "活跃",
|
|
@@ -263,10 +263,14 @@ const messages = {
|
|
|
263
263
|
"errorMessages.startNewChat": "開始新聊天",
|
|
264
264
|
"errorMessages.upgradeAtBuilder": "在 Builder.io 升級",
|
|
265
265
|
"feedback.inaccurate": "不準確",
|
|
266
|
+
"feedback.keyboardHint": "{{shortcut}} Enter 送出",
|
|
266
267
|
"feedback.notHelpful": "沒有幫助",
|
|
268
|
+
"feedback.placeholder": "告訴我們哪裡出了問題……",
|
|
269
|
+
"feedback.submit": "送出",
|
|
267
270
|
"feedback.thumbsDown": "不喜歡",
|
|
268
271
|
"feedback.thumbsUp": "喜歡",
|
|
269
272
|
"feedback.tooSlow": "太慢",
|
|
273
|
+
"feedback.whatWentWrong": "哪裡出了問題?",
|
|
270
274
|
"feedback.wrongTool": "工具錯誤",
|
|
271
275
|
"header.switchToCli": "切換到 CLI",
|
|
272
276
|
"history.active": "使用中",
|
|
@@ -267,10 +267,14 @@ export declare const englishAgentChatMessages: {
|
|
|
267
267
|
readonly "errorMessages.startNewChat": "Start new chat";
|
|
268
268
|
readonly "errorMessages.upgradeAtBuilder": "Upgrade at Builder.io";
|
|
269
269
|
readonly "feedback.inaccurate": "Inaccurate";
|
|
270
|
+
readonly "feedback.keyboardHint": "{{shortcut}} Enter to send";
|
|
270
271
|
readonly "feedback.notHelpful": "Not helpful";
|
|
272
|
+
readonly "feedback.placeholder": "Tell us what went wrong...";
|
|
273
|
+
readonly "feedback.submit": "Submit";
|
|
271
274
|
readonly "feedback.thumbsDown": "Thumbs down";
|
|
272
275
|
readonly "feedback.thumbsUp": "Thumbs up";
|
|
273
276
|
readonly "feedback.tooSlow": "Too slow";
|
|
277
|
+
readonly "feedback.whatWentWrong": "What went wrong?";
|
|
274
278
|
readonly "feedback.wrongTool": "Wrong tool";
|
|
275
279
|
readonly "header.switchToCli": "Switch to CLI";
|
|
276
280
|
readonly "history.active": "Active";
|
|
@@ -16,18 +16,18 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
|
|
|
16
16
|
error?: undefined;
|
|
17
17
|
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
|
-
count?: undefined;
|
|
20
19
|
updated: number;
|
|
21
20
|
error?: undefined;
|
|
22
21
|
ok?: undefined;
|
|
23
|
-
} | {
|
|
24
22
|
count?: undefined;
|
|
23
|
+
} | {
|
|
25
24
|
updated?: undefined;
|
|
26
25
|
error: string;
|
|
27
26
|
ok?: undefined;
|
|
28
|
-
} | {
|
|
29
27
|
count?: undefined;
|
|
28
|
+
} | {
|
|
30
29
|
updated?: undefined;
|
|
31
30
|
error?: undefined;
|
|
32
31
|
ok: boolean;
|
|
32
|
+
count?: undefined;
|
|
33
33
|
}>>;
|
|
@@ -30,6 +30,16 @@ export async function submitFeedback(opts) {
|
|
|
30
30
|
await insertFeedback(entry);
|
|
31
31
|
return entry;
|
|
32
32
|
}
|
|
33
|
+
function unwrapPersistedThreadMessage(value) {
|
|
34
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const record = value;
|
|
38
|
+
const nested = record.message;
|
|
39
|
+
return nested && typeof nested === "object" && !Array.isArray(nested)
|
|
40
|
+
? nested
|
|
41
|
+
: record;
|
|
42
|
+
}
|
|
33
43
|
async function getThreadMessages(threadId) {
|
|
34
44
|
await ensureObservabilityTables();
|
|
35
45
|
const client = getDbExec();
|
|
@@ -47,22 +57,36 @@ async function getThreadMessages(threadId) {
|
|
|
47
57
|
const messages = data.messages ?? data;
|
|
48
58
|
if (!Array.isArray(messages))
|
|
49
59
|
return [];
|
|
50
|
-
return messages
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
return messages.flatMap((value) => {
|
|
61
|
+
const message = unwrapPersistedThreadMessage(value);
|
|
62
|
+
if (!message)
|
|
63
|
+
return [];
|
|
64
|
+
const content = message.content;
|
|
65
|
+
if ((message.role !== "user" && message.role !== "assistant") ||
|
|
66
|
+
(typeof content !== "string" && !Array.isArray(content))) {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
const text = typeof content === "string"
|
|
70
|
+
? content
|
|
71
|
+
: content
|
|
72
|
+
.filter((part) => Boolean(part) &&
|
|
73
|
+
typeof part === "object" &&
|
|
74
|
+
!Array.isArray(part) &&
|
|
75
|
+
part.type === "text")
|
|
76
|
+
.map((part) => (typeof part.text === "string" ? part.text : ""))
|
|
77
|
+
.join("");
|
|
78
|
+
if (!text)
|
|
79
|
+
return [];
|
|
80
|
+
return [
|
|
81
|
+
{
|
|
82
|
+
role: message.role,
|
|
83
|
+
content: text,
|
|
84
|
+
createdAt: typeof message.createdAt === "number"
|
|
85
|
+
? message.createdAt
|
|
86
|
+
: undefined,
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
});
|
|
66
90
|
}
|
|
67
91
|
catch {
|
|
68
92
|
return [];
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* GET /traces/:runId — get trace detail (spans + summary)
|
|
9
9
|
* GET /traces/:runId/evals — get evals for a run
|
|
10
10
|
* POST /feedback — submit feedback
|
|
11
|
-
* GET /feedback?since=N&limit=N
|
|
11
|
+
* GET /feedback?since=N&limit=N&feedbackType=text — list feedback entries
|
|
12
12
|
* GET /feedback/stats?since=N — feedback aggregation stats
|
|
13
13
|
* GET /satisfaction?since=N — satisfaction scores
|
|
14
14
|
* GET /evals/stats?since=N — eval stats
|
|
@@ -41,27 +41,27 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
41
41
|
thumbsUpRate: number;
|
|
42
42
|
avgEvalScore: number;
|
|
43
43
|
} | {
|
|
44
|
+
error?: undefined;
|
|
45
|
+
ok?: undefined;
|
|
44
46
|
summary: import("./types.js").TraceSummary;
|
|
45
47
|
spans: import("./types.js").TraceSpan[];
|
|
46
48
|
id?: undefined;
|
|
49
|
+
} | {
|
|
47
50
|
error?: undefined;
|
|
48
51
|
ok?: undefined;
|
|
49
|
-
} | {
|
|
50
52
|
summary?: undefined;
|
|
51
53
|
spans?: undefined;
|
|
52
54
|
id: string;
|
|
53
|
-
error?: undefined;
|
|
54
|
-
ok?: undefined;
|
|
55
55
|
} | {
|
|
56
|
+
ok?: undefined;
|
|
56
57
|
summary?: undefined;
|
|
57
58
|
spans?: undefined;
|
|
58
59
|
id?: undefined;
|
|
59
60
|
error: any;
|
|
60
|
-
ok?: undefined;
|
|
61
61
|
} | {
|
|
62
|
+
error?: undefined;
|
|
62
63
|
summary?: undefined;
|
|
63
64
|
spans?: undefined;
|
|
64
65
|
id?: undefined;
|
|
65
|
-
error?: undefined;
|
|
66
66
|
ok: boolean;
|
|
67
67
|
}>>;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* GET /traces/:runId — get trace detail (spans + summary)
|
|
9
9
|
* GET /traces/:runId/evals — get evals for a run
|
|
10
10
|
* POST /feedback — submit feedback
|
|
11
|
-
* GET /feedback?since=N&limit=N
|
|
11
|
+
* GET /feedback?since=N&limit=N&feedbackType=text — list feedback entries
|
|
12
12
|
* GET /feedback/stats?since=N — feedback aggregation stats
|
|
13
13
|
* GET /satisfaction?since=N — satisfaction scores
|
|
14
14
|
* GET /evals/stats?since=N — eval stats
|
|
@@ -27,6 +27,16 @@ import { track } from "../tracking/registry.js";
|
|
|
27
27
|
import { emitAiFeedbackSurveyEvent } from "./posthog-ai.js";
|
|
28
28
|
import { getObservabilityOverview, getTraceSummaries, getTraceSummary, getTraceSpansForRun, getEvalsForRun, insertFeedback, getFeedback, getFeedbackStats, getSatisfactionScores, getEvalStats, listExperiments, insertExperiment, getExperiment, updateExperiment, getExperimentResults, } from "./store.js";
|
|
29
29
|
import { trackingIdentityProperties } from "./tracking-identity.js";
|
|
30
|
+
const FEEDBACK_TYPES = [
|
|
31
|
+
"thumbs_up",
|
|
32
|
+
"thumbs_down",
|
|
33
|
+
"category",
|
|
34
|
+
"text",
|
|
35
|
+
];
|
|
36
|
+
function isFeedbackType(value) {
|
|
37
|
+
return (typeof value === "string" &&
|
|
38
|
+
FEEDBACK_TYPES.includes(value));
|
|
39
|
+
}
|
|
30
40
|
function nanoid(size = 21) {
|
|
31
41
|
const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
32
42
|
let id = "";
|
|
@@ -143,8 +153,7 @@ export function createObservabilityHandler() {
|
|
|
143
153
|
return { error: "Invalid JSON body" };
|
|
144
154
|
}
|
|
145
155
|
const feedbackType = body?.feedbackType;
|
|
146
|
-
if (!feedbackType
|
|
147
|
-
!["thumbs_up", "thumbs_down", "category", "text"].includes(feedbackType)) {
|
|
156
|
+
if (!isFeedbackType(feedbackType)) {
|
|
148
157
|
setResponseStatus(event, 400);
|
|
149
158
|
return { error: "feedbackType is required" };
|
|
150
159
|
}
|
|
@@ -229,6 +238,9 @@ export function createObservabilityHandler() {
|
|
|
229
238
|
return getFeedback({
|
|
230
239
|
sinceMs: parseSince(q),
|
|
231
240
|
limit: parseLimit(q),
|
|
241
|
+
feedbackType: isFeedbackType(q.feedbackType)
|
|
242
|
+
? q.feedbackType
|
|
243
|
+
: undefined,
|
|
232
244
|
userId: owner,
|
|
233
245
|
});
|
|
234
246
|
}
|
|
@@ -197,6 +197,7 @@ export async function ensureObservabilityTables() {
|
|
|
197
197
|
await ensureIndexExists("idx_feedback_thread", `CREATE INDEX IF NOT EXISTS idx_feedback_thread ON agent_feedback (thread_id)`);
|
|
198
198
|
await ensureIndexExists("idx_feedback_created", `CREATE INDEX IF NOT EXISTS idx_feedback_created ON agent_feedback (created_at)`);
|
|
199
199
|
await ensureIndexExists("idx_feedback_user", `CREATE INDEX IF NOT EXISTS idx_feedback_user ON agent_feedback (user_id, created_at)`);
|
|
200
|
+
await ensureIndexExists("idx_feedback_type_created", `CREATE INDEX IF NOT EXISTS idx_feedback_type_created ON agent_feedback (feedback_type, created_at)`);
|
|
200
201
|
await ensureIndexExists("idx_satisfaction_thread", `CREATE INDEX IF NOT EXISTS idx_satisfaction_thread ON agent_satisfaction_scores (thread_id)`);
|
|
201
202
|
await ensureIndexExists("idx_satisfaction_user", `CREATE INDEX IF NOT EXISTS idx_satisfaction_user ON agent_satisfaction_scores (user_id, computed_at)`);
|
|
202
203
|
await ensureIndexExists("idx_evals_run", `CREATE INDEX IF NOT EXISTS idx_evals_run ON agent_evals (run_id)`);
|
|
@@ -252,6 +253,7 @@ export async function ensureObservabilityTables() {
|
|
|
252
253
|
`CREATE INDEX IF NOT EXISTS idx_feedback_thread ON agent_feedback (thread_id)`,
|
|
253
254
|
`CREATE INDEX IF NOT EXISTS idx_feedback_created ON agent_feedback (created_at)`,
|
|
254
255
|
`CREATE INDEX IF NOT EXISTS idx_feedback_user ON agent_feedback (user_id, created_at)`,
|
|
256
|
+
`CREATE INDEX IF NOT EXISTS idx_feedback_type_created ON agent_feedback (feedback_type, created_at)`,
|
|
255
257
|
`CREATE INDEX IF NOT EXISTS idx_satisfaction_thread ON agent_satisfaction_scores (thread_id)`,
|
|
256
258
|
`CREATE INDEX IF NOT EXISTS idx_satisfaction_user ON agent_satisfaction_scores (user_id, computed_at)`,
|
|
257
259
|
`CREATE INDEX IF NOT EXISTS idx_evals_run ON agent_evals (run_id)`,
|
|
@@ -637,7 +637,11 @@ export async function instrumentAgentLoop(opts) {
|
|
|
637
637
|
catch { }
|
|
638
638
|
let llmCallCount = 0;
|
|
639
639
|
if (usage || runStatus === "error") {
|
|
640
|
-
llmCallCount =
|
|
640
|
+
llmCallCount =
|
|
641
|
+
usage?.llmCalls ??
|
|
642
|
+
// Compatibility for custom loop implementations that predate the
|
|
643
|
+
// attempt counter: a measured run still counts as one call.
|
|
644
|
+
1;
|
|
641
645
|
const generationUsage = usage ?? {
|
|
642
646
|
inputTokens: 0,
|
|
643
647
|
outputTokens: 0,
|
|
@@ -75,9 +75,7 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
-
|
|
79
|
-
id?: undefined;
|
|
80
|
-
provider?: undefined;
|
|
78
|
+
found?: undefined;
|
|
81
79
|
deleted?: undefined;
|
|
82
80
|
providers: {
|
|
83
81
|
id: string;
|
|
@@ -89,45 +87,47 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
89
87
|
updatedAt: number;
|
|
90
88
|
}[];
|
|
91
89
|
count: number;
|
|
92
|
-
|
|
90
|
+
provider?: undefined;
|
|
93
91
|
registered?: undefined;
|
|
92
|
+
id?: undefined;
|
|
94
93
|
label?: undefined;
|
|
95
|
-
} | {
|
|
96
94
|
message?: undefined;
|
|
97
|
-
|
|
98
|
-
id?: undefined;
|
|
95
|
+
} | {
|
|
99
96
|
deleted?: undefined;
|
|
100
97
|
providers?: undefined;
|
|
98
|
+
count?: undefined;
|
|
101
99
|
found: boolean;
|
|
102
100
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
103
101
|
registered?: undefined;
|
|
102
|
+
id?: undefined;
|
|
104
103
|
label?: undefined;
|
|
105
|
-
} | {
|
|
106
104
|
message?: undefined;
|
|
107
|
-
|
|
108
|
-
provider?: undefined;
|
|
105
|
+
} | {
|
|
109
106
|
deleted?: undefined;
|
|
110
107
|
providers?: undefined;
|
|
108
|
+
count?: undefined;
|
|
109
|
+
provider?: undefined;
|
|
111
110
|
found: boolean;
|
|
112
111
|
id: string;
|
|
113
112
|
registered?: undefined;
|
|
114
113
|
label?: undefined;
|
|
115
|
-
} | {
|
|
116
114
|
message?: undefined;
|
|
115
|
+
} | {
|
|
116
|
+
found?: undefined;
|
|
117
|
+
providers?: undefined;
|
|
117
118
|
count?: undefined;
|
|
118
119
|
provider?: undefined;
|
|
119
|
-
providers?: undefined;
|
|
120
|
-
found?: undefined;
|
|
121
120
|
deleted: boolean;
|
|
122
121
|
id: string;
|
|
123
122
|
registered?: undefined;
|
|
124
123
|
label?: undefined;
|
|
124
|
+
message?: undefined;
|
|
125
125
|
} | {
|
|
126
|
-
|
|
127
|
-
provider?: undefined;
|
|
126
|
+
found?: undefined;
|
|
128
127
|
deleted?: undefined;
|
|
129
128
|
providers?: undefined;
|
|
130
|
-
|
|
129
|
+
count?: undefined;
|
|
130
|
+
provider?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|
|
133
133
|
label: string;
|
|
@@ -311,8 +311,11 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
311
311
|
notes?: string | undefined;
|
|
312
312
|
scope?: "org" | "user" | undefined;
|
|
313
313
|
}, {
|
|
314
|
-
deleted?: undefined;
|
|
315
314
|
id?: undefined;
|
|
315
|
+
provider?: undefined;
|
|
316
|
+
deleted?: undefined;
|
|
317
|
+
found?: undefined;
|
|
318
|
+
message?: undefined;
|
|
316
319
|
providers: {
|
|
317
320
|
id: string;
|
|
318
321
|
label: string;
|
|
@@ -323,47 +326,44 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
323
326
|
updatedAt: number;
|
|
324
327
|
}[];
|
|
325
328
|
count: number;
|
|
326
|
-
provider?: undefined;
|
|
327
|
-
found?: undefined;
|
|
328
329
|
registered?: undefined;
|
|
329
330
|
label?: undefined;
|
|
330
|
-
message?: undefined;
|
|
331
331
|
} | {
|
|
332
|
-
deleted?: undefined;
|
|
333
332
|
id?: undefined;
|
|
333
|
+
deleted?: undefined;
|
|
334
|
+
message?: undefined;
|
|
334
335
|
providers?: undefined;
|
|
335
336
|
count?: undefined;
|
|
336
337
|
found: boolean;
|
|
337
338
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
338
339
|
registered?: undefined;
|
|
339
340
|
label?: undefined;
|
|
340
|
-
message?: undefined;
|
|
341
341
|
} | {
|
|
342
|
+
provider?: undefined;
|
|
342
343
|
deleted?: undefined;
|
|
344
|
+
message?: undefined;
|
|
343
345
|
providers?: undefined;
|
|
344
346
|
count?: undefined;
|
|
345
|
-
provider?: undefined;
|
|
346
347
|
found: boolean;
|
|
347
348
|
id: string;
|
|
348
349
|
registered?: undefined;
|
|
349
350
|
label?: undefined;
|
|
350
|
-
message?: undefined;
|
|
351
351
|
} | {
|
|
352
|
-
providers?: undefined;
|
|
353
|
-
count?: undefined;
|
|
354
352
|
provider?: undefined;
|
|
355
353
|
found?: undefined;
|
|
354
|
+
message?: undefined;
|
|
355
|
+
providers?: undefined;
|
|
356
|
+
count?: undefined;
|
|
356
357
|
deleted: boolean;
|
|
357
358
|
id: string;
|
|
358
359
|
registered?: undefined;
|
|
359
360
|
label?: undefined;
|
|
360
|
-
message?: undefined;
|
|
361
361
|
} | {
|
|
362
|
+
provider?: undefined;
|
|
362
363
|
deleted?: undefined;
|
|
364
|
+
found?: undefined;
|
|
363
365
|
providers?: undefined;
|
|
364
366
|
count?: undefined;
|
|
365
|
-
provider?: undefined;
|
|
366
|
-
found?: undefined;
|
|
367
367
|
registered: boolean;
|
|
368
368
|
id: string;
|
|
369
369
|
label: string;
|
|
@@ -73,7 +73,6 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
73
73
|
offset?: unknown;
|
|
74
74
|
limit?: unknown;
|
|
75
75
|
}, {
|
|
76
|
-
deleted?: undefined;
|
|
77
76
|
jobs: {
|
|
78
77
|
id: string;
|
|
79
78
|
name: string;
|
|
@@ -84,6 +83,7 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
84
83
|
updatedAt: string;
|
|
85
84
|
}[];
|
|
86
85
|
total: number;
|
|
86
|
+
deleted?: undefined;
|
|
87
87
|
jobId?: undefined;
|
|
88
88
|
} | {
|
|
89
89
|
jobs?: undefined;
|
|
@@ -91,9 +91,9 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
91
91
|
deleted: boolean;
|
|
92
92
|
jobId: string;
|
|
93
93
|
} | {
|
|
94
|
-
deleted?: undefined;
|
|
95
94
|
jobs?: undefined;
|
|
96
95
|
total?: undefined;
|
|
96
|
+
deleted?: undefined;
|
|
97
97
|
jobId?: undefined;
|
|
98
98
|
hits: Record<string, unknown>[];
|
|
99
99
|
offset: number;
|
|
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
|
|
|
48
48
|
}>;
|
|
49
49
|
/** DELETE /_agent-native/resources/:id — delete a resource */
|
|
50
50
|
export declare function handleDeleteResource(event: any): Promise<{
|
|
51
|
-
ok?: undefined;
|
|
52
51
|
error: string;
|
|
52
|
+
ok?: undefined;
|
|
53
53
|
} | {
|
|
54
54
|
error?: undefined;
|
|
55
55
|
ok: boolean;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -34,37 +34,37 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
|
|
|
34
34
|
/** POST /_agent-native/secrets/:key — write a secret. */
|
|
35
35
|
export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
36
36
|
error: string;
|
|
37
|
-
status?: undefined;
|
|
38
37
|
ok?: undefined;
|
|
38
|
+
status?: undefined;
|
|
39
39
|
} | {
|
|
40
|
+
error?: undefined;
|
|
40
41
|
ok: boolean;
|
|
41
42
|
status: string;
|
|
42
|
-
error?: undefined;
|
|
43
43
|
} | {
|
|
44
|
+
ok?: undefined;
|
|
44
45
|
error: string;
|
|
45
46
|
removed?: undefined;
|
|
46
|
-
ok?: undefined;
|
|
47
47
|
} | {
|
|
48
|
+
error?: undefined;
|
|
48
49
|
ok: boolean;
|
|
49
50
|
removed: boolean;
|
|
50
|
-
error?: undefined;
|
|
51
51
|
}>>;
|
|
52
52
|
/**
|
|
53
53
|
* POST /_agent-native/secrets/:key/test — validate an optional candidate value
|
|
54
54
|
* or the current stored value without changing anything.
|
|
55
55
|
*/
|
|
56
56
|
export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
57
|
+
ok?: undefined;
|
|
57
58
|
error: string;
|
|
58
59
|
note?: undefined;
|
|
59
|
-
ok?: undefined;
|
|
60
60
|
} | {
|
|
61
|
+
error?: undefined;
|
|
61
62
|
ok: boolean;
|
|
62
63
|
note?: undefined;
|
|
63
|
-
error?: undefined;
|
|
64
64
|
} | {
|
|
65
|
+
error?: undefined;
|
|
65
66
|
ok: boolean;
|
|
66
67
|
note: string;
|
|
67
|
-
error?: undefined;
|
|
68
68
|
} | {
|
|
69
69
|
note?: undefined;
|
|
70
70
|
ok: boolean;
|
|
@@ -95,11 +95,11 @@ export interface AdHocSecretPayload {
|
|
|
95
95
|
export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
|
|
96
96
|
error: string;
|
|
97
97
|
} | {
|
|
98
|
+
error?: undefined;
|
|
98
99
|
ok: boolean;
|
|
99
100
|
key: string;
|
|
100
|
-
error?: undefined;
|
|
101
101
|
} | {
|
|
102
|
+
error?: undefined;
|
|
102
103
|
ok: boolean;
|
|
103
104
|
removed: boolean;
|
|
104
|
-
error?: undefined;
|
|
105
105
|
}>>;
|
|
@@ -14,12 +14,14 @@ export type ActionRouteResolvedCaller = AgentRunOwnerContext & {
|
|
|
14
14
|
* Org to scope the request to, verified from the same credential as the
|
|
15
15
|
* caller identity (e.g. the A2A token's org claim). When omitted, the org
|
|
16
16
|
* is derived from the verified owner email via the framework's owner→org
|
|
17
|
-
* membership lookup.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* membership lookup. An explicit `null` means the verified caller has no
|
|
18
|
+
* org and must not fall back to another membership. The ambient session/org
|
|
19
|
+
* state on the request is never consulted for adapter-resolved callers: a
|
|
20
|
+
* request can carry both a valid A2A bearer and an unrelated browser cookie,
|
|
21
|
+
* and the cookie user's org must not leak into the token caller's request
|
|
22
|
+
* context.
|
|
21
23
|
*/
|
|
22
|
-
orgId?: string;
|
|
24
|
+
orgId?: string | null;
|
|
23
25
|
/** Verified A2A correlation and issuer metadata for the audit row. */
|
|
24
26
|
delegationJti?: string;
|
|
25
27
|
delegationIssuer?: string;
|
|
@@ -3,12 +3,13 @@ import { verifyA2ATokenWithClaims } from "../a2a-claims.js";
|
|
|
3
3
|
import { isActionContractError, isAgentActionStopError } from "../action.js";
|
|
4
4
|
import { isTransientDatabaseError } from "../db/client.js";
|
|
5
5
|
import { declaresFeatureFlagDelegation } from "../feature-flags/a2a-action-route.js";
|
|
6
|
+
import { isFeatureFlagAdminEmail } from "../feature-flags/permissions.js";
|
|
6
7
|
import { resolveOrgByDomain, resolveOrgIdForEmail } from "../org/context.js";
|
|
7
8
|
import { readBody } from "../server/h3-helpers.js";
|
|
8
9
|
import { EMBED_TARGET_HEADER } from "../shared/embed-auth.js";
|
|
9
10
|
import { isMcpEmbedCorsOrigin, MCP_EMBED_CORS_ALLOW_HEADERS, shouldAllowMcpEmbedCredentials, } from "../shared/mcp-embed-headers.js";
|
|
10
11
|
import { actionCallIsReadOnly, notifyActionChange } from "./action-change.js";
|
|
11
|
-
import { readBrowserSessionIdHeader, seedAgentRunOwnerContext, } from "./agent-run-context.js";
|
|
12
|
+
import { readBrowserSessionIdHeader, readAnalyticsClientPlatformHeader, seedAgentRunOwnerContext, } from "./agent-run-context.js";
|
|
12
13
|
import { captureError } from "./capture-error.js";
|
|
13
14
|
import { getAllowedCorsOrigin as resolveAllowedCorsOrigin, readCorsAllowedOrigins, } from "./cors-origins.js";
|
|
14
15
|
import { resolveEmbedSessionFromRequest, resolvedEmbedCapabilityScope, } from "./embed-session.js";
|
|
@@ -55,7 +56,7 @@ async function resolveFeatureFlagA2ACaller(event, actionName) {
|
|
|
55
56
|
if (!claims || !claims.scope.includes(required))
|
|
56
57
|
throw new Error("Invalid feature flag delegation");
|
|
57
58
|
const localOrg = await resolveOrgByDomain(claims.orgDomain);
|
|
58
|
-
if (!localOrg)
|
|
59
|
+
if (!localOrg && !isFeatureFlagAdminEmail(claims.email))
|
|
59
60
|
throw new Error("Invalid feature flag delegation");
|
|
60
61
|
if (actionName === "set-feature-flag" &&
|
|
61
62
|
(await consumeOneTimeJti(claims.jti))) {
|
|
@@ -63,7 +64,7 @@ async function resolveFeatureFlagA2ACaller(event, actionName) {
|
|
|
63
64
|
}
|
|
64
65
|
return {
|
|
65
66
|
owner: claims.email,
|
|
66
|
-
orgId: localOrg
|
|
67
|
+
orgId: localOrg?.orgId ?? null,
|
|
67
68
|
anonymous: false,
|
|
68
69
|
delegationJti: claims.jti,
|
|
69
70
|
delegationIssuer: claims.issuer,
|
|
@@ -167,7 +168,7 @@ function handleOptionsRequest(event) {
|
|
|
167
168
|
}
|
|
168
169
|
setResponseHeader(event, "Access-Control-Allow-Methods", "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS");
|
|
169
170
|
setResponseHeader(event, "Access-Control-Allow-Headers", cors.credentials
|
|
170
|
-
? `Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Session-Id,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id,${EMBED_TARGET_HEADER}`
|
|
171
|
+
? `Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Session-Id,X-Agent-Native-Client-Platform,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id,${EMBED_TARGET_HEADER}`
|
|
171
172
|
: `${MCP_EMBED_CORS_ALLOW_HEADERS},X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id`);
|
|
172
173
|
}
|
|
173
174
|
setResponseStatus(event, 204);
|
|
@@ -362,7 +363,8 @@ export function mountActionRoutes(nitroApp, actions, options) {
|
|
|
362
363
|
}
|
|
363
364
|
// Org scoping. For adapter-resolved callers the org must come
|
|
364
365
|
// exclusively from the verified credential: the adapter-asserted
|
|
365
|
-
// orgId when present,
|
|
366
|
+
// orgId when present, explicit null when the caller has no org,
|
|
367
|
+
// otherwise the owner-email membership lookup.
|
|
366
368
|
// The request's ambient session/org state (`resolveOrgId`, usually
|
|
367
369
|
// getSession-backed) is deliberately NOT consulted — a request can
|
|
368
370
|
// carry both a valid A2A bearer and an unrelated same-origin browser
|
|
@@ -372,7 +374,10 @@ export function mountActionRoutes(nitroApp, actions, options) {
|
|
|
372
374
|
let orgId;
|
|
373
375
|
if (resolvedCaller) {
|
|
374
376
|
orgId = normalizeOrgId(resolvedCaller.orgId);
|
|
375
|
-
if (
|
|
377
|
+
if (resolvedCaller.orgId !== null &&
|
|
378
|
+
!orgId &&
|
|
379
|
+
resolvedCaller.owner &&
|
|
380
|
+
!resolvedCaller.anonymous) {
|
|
376
381
|
orgId = await storedActiveOrgId(resolvedCaller.owner);
|
|
377
382
|
}
|
|
378
383
|
}
|
|
@@ -385,6 +390,7 @@ export function mountActionRoutes(nitroApp, actions, options) {
|
|
|
385
390
|
}
|
|
386
391
|
const timezone = readTimezoneHeader(event);
|
|
387
392
|
const browserSessionId = readBrowserSessionIdHeader(event);
|
|
393
|
+
const clientPlatform = readAnalyticsClientPlatformHeader(event);
|
|
388
394
|
return runWithRequestContext({
|
|
389
395
|
userEmail,
|
|
390
396
|
userName,
|
|
@@ -392,6 +398,7 @@ export function mountActionRoutes(nitroApp, actions, options) {
|
|
|
392
398
|
authCapability,
|
|
393
399
|
timezone,
|
|
394
400
|
browserSessionId,
|
|
401
|
+
clientPlatform,
|
|
395
402
|
requestOrigin: getRequestURL(event).origin,
|
|
396
403
|
// Captured here because this is the last layer that still holds
|
|
397
404
|
// the h3 event; everything below reads it off the request store.
|
|
@@ -35,6 +35,7 @@ import { getSkillNameFromPath } from "../resources/metadata.js";
|
|
|
35
35
|
import { resourceList, resourceListAccessible, resourceGet, ensurePersonalDefaults, SHARED_OWNER, WORKSPACE_OWNER, } from "../resources/store.js";
|
|
36
36
|
import { normalizeDatabaseToolsMode } from "../scripts/db/tool-mode.js";
|
|
37
37
|
import { getSetting, putSetting } from "../settings/store.js";
|
|
38
|
+
import { ANALYTICS_CLIENT_PLATFORM_BODY_FIELD, normalizeAnalyticsClientPlatform, } from "../shared/analytics-platform.js";
|
|
38
39
|
import { docsUrl } from "../shared/docs-url.js";
|
|
39
40
|
import { handleSharedThreadRequest, } from "./agent-chat/shared-thread.js";
|
|
40
41
|
import { discoverAgents } from "./agent-discovery.js";
|
|
@@ -4909,6 +4910,11 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
4909
4910
|
// is already consumed, so the handler reads this instead.
|
|
4910
4911
|
event.context = event.context ?? {};
|
|
4911
4912
|
event.context.__agentChatBackgroundBody = workerBody;
|
|
4913
|
+
const persistedClientPlatform = normalizeAnalyticsClientPlatform(workerBody[ANALYTICS_CLIENT_PLATFORM_BODY_FIELD]);
|
|
4914
|
+
if (persistedClientPlatform) {
|
|
4915
|
+
event.context[ANALYTICS_CLIENT_PLATFORM_BODY_FIELD] =
|
|
4916
|
+
persistedClientPlatform;
|
|
4917
|
+
}
|
|
4912
4918
|
// Durable owner context: this self-dispatch is cookieless (HMAC-only).
|
|
4913
4919
|
// Resolve the owner from the persisted run row, never the request
|
|
4914
4920
|
// body, then invoke the normal handler. The shared agent-run context
|