@agent-native/core 0.222.0-nightly-20261029004912 → 0.222.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/agent/production-agent.js +22 -9
- package/dist/agent/run-store.d.ts +9 -1
- package/dist/agent/run-store.js +26 -3
- package/dist/cli/code-agent-mcp-config.js +6 -1
- package/dist/client/chat/agentkit-agent-native.js +1 -2
- package/dist/client/chat/agentkit-protocol.js +14 -0
- package/dist/client/chat/runtime.d.ts +5 -1
- package/dist/client/chat/runtime.js +23 -1
- package/dist/client/sse-event-processor.d.ts +10 -0
- package/dist/client/sse-event-processor.js +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +1 -1
- package/dist/connections/catalog.js +4 -11
- package/dist/mcp-client/config.d.ts +6 -0
- package/dist/mcp-client/manager.js +25 -2
- package/dist/mcp-client/routes.js +2 -0
- package/dist/mcp-client/workspace-connection-servers.d.ts +30 -0
- package/dist/mcp-client/workspace-connection-servers.js +119 -0
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/provider-api/actions/provider-api.js +2 -0
- package/dist/provider-api/agent-request-policy.d.ts +13 -0
- package/dist/provider-api/agent-request-policy.js +31 -0
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/corpus-jobs.js +7 -1
- package/dist/provider-api/index.d.ts +4 -1
- package/dist/provider-api/index.js +4 -1
- package/dist/provider-api/read-only-requests.js +11 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +4 -4
- package/dist/server/action-discovery.js +6 -0
- package/dist/server/agent-chat/process-run-failure.js +58 -2
- package/dist/server/agent-engine-api-key-route.d.ts +3 -3
- package/dist/server/workspace-provider-oauth.d.ts +1 -0
- package/dist/server/workspace-provider-oauth.js +10 -2
- package/dist/templates/chat/.agents/skills/actions/references/provider-apis.md +13 -0
- package/dist/templates/default/.agents/skills/actions/references/provider-apis.md +13 -0
- package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +10 -4
- package/dist/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +287 -0
- package/dist/templates/factory/.agents/skills/review-prs/SKILL.md +266 -92
- package/dist/templates/headless/.agents/skills/actions/references/provider-apis.md +13 -0
- package/dist/templates/workspace-core/.agents/skills/actions/references/provider-apis.md +13 -0
- package/dist/vite/action-types-plugin.js +4 -0
- package/dist/workspace-connections/actions/list-workspace-connection-scopes.d.ts +16 -0
- package/dist/workspace-connections/actions/list-workspace-connection-scopes.js +62 -0
- package/package.json +5 -4
- package/src/templates/chat/.agents/skills/actions/references/provider-apis.md +13 -0
- package/src/templates/default/.agents/skills/actions/references/provider-apis.md +13 -0
- package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +10 -4
- package/src/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +287 -0
- package/src/templates/factory/.agents/skills/review-prs/SKILL.md +266 -92
- package/src/templates/headless/.agents/skills/actions/references/provider-apis.md +13 -0
- package/src/templates/workspace-core/.agents/skills/actions/references/provider-apis.md +13 -0
|
@@ -77,7 +77,6 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
78
|
id?: undefined;
|
|
79
79
|
deleted?: undefined;
|
|
80
|
-
provider?: undefined;
|
|
81
80
|
message?: undefined;
|
|
82
81
|
found?: undefined;
|
|
83
82
|
providers: {
|
|
@@ -90,44 +89,45 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
90
89
|
updatedAt: number;
|
|
91
90
|
}[];
|
|
92
91
|
count: number;
|
|
92
|
+
provider?: undefined;
|
|
93
93
|
registered?: undefined;
|
|
94
94
|
label?: undefined;
|
|
95
95
|
} | {
|
|
96
96
|
id?: undefined;
|
|
97
|
+
count?: undefined;
|
|
97
98
|
deleted?: undefined;
|
|
98
99
|
message?: undefined;
|
|
99
100
|
providers?: undefined;
|
|
100
|
-
count?: undefined;
|
|
101
101
|
found: boolean;
|
|
102
102
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
103
103
|
registered?: undefined;
|
|
104
104
|
label?: undefined;
|
|
105
105
|
} | {
|
|
106
|
+
count?: undefined;
|
|
106
107
|
deleted?: undefined;
|
|
107
|
-
provider?: undefined;
|
|
108
108
|
message?: undefined;
|
|
109
109
|
providers?: undefined;
|
|
110
|
-
|
|
110
|
+
provider?: undefined;
|
|
111
111
|
found: boolean;
|
|
112
112
|
id: string;
|
|
113
113
|
registered?: undefined;
|
|
114
114
|
label?: undefined;
|
|
115
115
|
} | {
|
|
116
|
-
|
|
116
|
+
count?: undefined;
|
|
117
117
|
message?: undefined;
|
|
118
118
|
found?: undefined;
|
|
119
119
|
providers?: undefined;
|
|
120
|
-
|
|
120
|
+
provider?: undefined;
|
|
121
121
|
deleted: boolean;
|
|
122
122
|
id: string;
|
|
123
123
|
registered?: undefined;
|
|
124
124
|
label?: undefined;
|
|
125
125
|
} | {
|
|
126
|
+
count?: undefined;
|
|
126
127
|
deleted?: undefined;
|
|
127
|
-
provider?: undefined;
|
|
128
128
|
found?: undefined;
|
|
129
129
|
providers?: undefined;
|
|
130
|
-
|
|
130
|
+
provider?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|
|
133
133
|
label: string;
|
|
@@ -319,7 +319,6 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
319
319
|
id?: undefined;
|
|
320
320
|
message?: undefined;
|
|
321
321
|
found?: undefined;
|
|
322
|
-
deleted?: undefined;
|
|
323
322
|
providers: {
|
|
324
323
|
id: string;
|
|
325
324
|
label: string;
|
|
@@ -331,26 +330,27 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
331
330
|
}[];
|
|
332
331
|
count: number;
|
|
333
332
|
provider?: undefined;
|
|
333
|
+
deleted?: undefined;
|
|
334
334
|
registered?: undefined;
|
|
335
335
|
label?: undefined;
|
|
336
336
|
} | {
|
|
337
337
|
id?: undefined;
|
|
338
338
|
count?: undefined;
|
|
339
339
|
message?: undefined;
|
|
340
|
-
deleted?: undefined;
|
|
341
340
|
providers?: undefined;
|
|
342
341
|
found: boolean;
|
|
343
342
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
343
|
+
deleted?: undefined;
|
|
344
344
|
registered?: undefined;
|
|
345
345
|
label?: undefined;
|
|
346
346
|
} | {
|
|
347
347
|
count?: undefined;
|
|
348
348
|
message?: undefined;
|
|
349
|
-
deleted?: undefined;
|
|
350
349
|
providers?: undefined;
|
|
351
350
|
provider?: undefined;
|
|
352
351
|
found: boolean;
|
|
353
352
|
id: string;
|
|
353
|
+
deleted?: undefined;
|
|
354
354
|
registered?: undefined;
|
|
355
355
|
label?: undefined;
|
|
356
356
|
} | {
|
|
@@ -366,9 +366,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
366
366
|
} | {
|
|
367
367
|
count?: undefined;
|
|
368
368
|
found?: undefined;
|
|
369
|
-
deleted?: undefined;
|
|
370
369
|
providers?: undefined;
|
|
371
370
|
provider?: undefined;
|
|
371
|
+
deleted?: undefined;
|
|
372
372
|
registered: boolean;
|
|
373
373
|
id: string;
|
|
374
374
|
label: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineAction, } from "../../action.js";
|
|
3
3
|
import { getCredentialContext } from "../../server/request-context.js";
|
|
4
|
+
import { assertAgentProviderRequestAllowed } from "../agent-request-policy.js";
|
|
4
5
|
import { isReadOnlyProviderPost } from "../read-only-requests.js";
|
|
5
6
|
import { rejectFailedProviderResult } from "../result-outcome.js";
|
|
6
7
|
import { stagingExecuteRequest } from "../staging.js";
|
|
@@ -261,6 +262,7 @@ export function createProviderApiRequestAction(runtime, options = {}) {
|
|
|
261
262
|
grounding: true,
|
|
262
263
|
run: async (rawArgs) => {
|
|
263
264
|
const args = rawArgs;
|
|
265
|
+
assertAgentProviderRequestAllowed(args);
|
|
264
266
|
if (args.stageAs) {
|
|
265
267
|
if (!options.appId) {
|
|
266
268
|
throw new Error("createProviderApiRequestAction requires appId when stageAs is used.");
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Whether agent-supplied provider requests are limited to reads for a provider. */
|
|
2
|
+
export declare function providerApiAgentRequestsReadOnly(provider: string): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Refuse a write in a request an agent supplied for a read-only provider.
|
|
5
|
+
* Every agent-facing action that forwards a caller-built request (request,
|
|
6
|
+
* corpus jobs) calls this before executing or storing it.
|
|
7
|
+
*/
|
|
8
|
+
export declare function assertAgentProviderRequestAllowed(request: {
|
|
9
|
+
provider: string;
|
|
10
|
+
method?: string | null;
|
|
11
|
+
path: string;
|
|
12
|
+
body?: unknown;
|
|
13
|
+
}): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { fail } from "../action.js";
|
|
2
|
+
import { isReadOnlyProviderPost } from "./read-only-requests.js";
|
|
3
|
+
/**
|
|
4
|
+
* Built-in providers the generic agent request tools may only read. Writes go
|
|
5
|
+
* through the provider's MCP tools or app-defined actions, which can enforce
|
|
6
|
+
* their own limits; server code calling `executeRequest` is unaffected.
|
|
7
|
+
*
|
|
8
|
+
* Kept out of `./index.js` so the shared request action only needs types from
|
|
9
|
+
* the runtime module, and template specs that mock it keep working.
|
|
10
|
+
*/
|
|
11
|
+
const AGENT_READ_ONLY_PROVIDERS = new Set(["hubspot"]);
|
|
12
|
+
/** Whether agent-supplied provider requests are limited to reads for a provider. */
|
|
13
|
+
export function providerApiAgentRequestsReadOnly(provider) {
|
|
14
|
+
return AGENT_READ_ONLY_PROVIDERS.has(provider);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Refuse a write in a request an agent supplied for a read-only provider.
|
|
18
|
+
* Every agent-facing action that forwards a caller-built request (request,
|
|
19
|
+
* corpus jobs) calls this before executing or storing it.
|
|
20
|
+
*/
|
|
21
|
+
export function assertAgentProviderRequestAllowed(request) {
|
|
22
|
+
if (!providerApiAgentRequestsReadOnly(String(request.provider)))
|
|
23
|
+
return;
|
|
24
|
+
const method = String(request.method ?? "GET").toUpperCase();
|
|
25
|
+
if (method === "GET" ||
|
|
26
|
+
method === "HEAD" ||
|
|
27
|
+
isReadOnlyProviderPost(request)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
fail(`${String(request.provider)} requests from agent tools are read-only. Make the change with the provider's MCP tools or an app action built for it.`, { errorCode: "provider_writes_not_allowed", statusCode: 403 });
|
|
31
|
+
}
|
|
@@ -73,6 +73,7 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
73
73
|
offset?: unknown;
|
|
74
74
|
limit?: unknown;
|
|
75
75
|
}, {
|
|
76
|
+
deleted?: undefined;
|
|
76
77
|
jobs: {
|
|
77
78
|
id: string;
|
|
78
79
|
name: string;
|
|
@@ -83,7 +84,6 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
83
84
|
updatedAt: string;
|
|
84
85
|
}[];
|
|
85
86
|
total: number;
|
|
86
|
-
deleted?: undefined;
|
|
87
87
|
jobId?: undefined;
|
|
88
88
|
} | {
|
|
89
89
|
jobs?: undefined;
|
|
@@ -91,9 +91,9 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
91
91
|
deleted: boolean;
|
|
92
92
|
jobId: string;
|
|
93
93
|
} | {
|
|
94
|
+
deleted?: undefined;
|
|
94
95
|
jobs?: undefined;
|
|
95
96
|
total?: undefined;
|
|
96
|
-
deleted?: undefined;
|
|
97
97
|
jobId?: undefined;
|
|
98
98
|
hits: Record<string, unknown>[];
|
|
99
99
|
offset: number;
|
|
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { defineAction } from "../action.js";
|
|
4
4
|
import { getCredentialContext } from "../server/request-context.js";
|
|
5
|
+
import { assertAgentProviderRequestAllowed } from "./agent-request-policy.js";
|
|
5
6
|
import { appendProviderCorpusJobHits, createProviderCorpusJob, deleteProviderCorpusJob, getProviderCorpusJob, getProviderCorpusJobHits, listProviderCorpusJobs, updateProviderCorpusJob, } from "./corpus-jobs-store.js";
|
|
6
7
|
import { setBodyValueAtPath } from "./request-body.js";
|
|
7
8
|
import { getStagedDatasetMeta, getStagedDatasetRows, stagedDatasetVersion, } from "./staged-datasets-store.js";
|
|
@@ -325,6 +326,7 @@ async function startJob(args, appId, ownerEmail) {
|
|
|
325
326
|
throw new Error("start requires mode.");
|
|
326
327
|
if (!args.request)
|
|
327
328
|
throw new Error("start requires request.");
|
|
329
|
+
assertAgentProviderRequestAllowed(args.request);
|
|
328
330
|
const search = args.search ?? {};
|
|
329
331
|
if (!hasSearchNeedle(search)) {
|
|
330
332
|
throw new Error("start requires search.query, search.queries, search.terms, or search.regex.");
|
|
@@ -666,7 +668,11 @@ async function pauseForBudget(job, checkpoint) {
|
|
|
666
668
|
})) ?? job);
|
|
667
669
|
}
|
|
668
670
|
async function callProvider(runtime, request) {
|
|
669
|
-
|
|
671
|
+
// Also checked here, not only at start: a job stored before a provider
|
|
672
|
+
// became read-only must not replay its write on continue.
|
|
673
|
+
const cleaned = cleanRequest(request);
|
|
674
|
+
assertAgentProviderRequestAllowed(cleaned);
|
|
675
|
+
const raw = (await runtime.executeRequest(cleaned));
|
|
670
676
|
const response = raw.response;
|
|
671
677
|
if (!response) {
|
|
672
678
|
return { body: raw };
|
|
@@ -527,7 +527,10 @@ export declare function executeProviderApiRequest(args: ProviderApiRequestArgs,
|
|
|
527
527
|
/**
|
|
528
528
|
* Resolve a provider OAuth token for a trusted server-side integration bridge
|
|
529
529
|
* such as a CRM adapter or Google Picker. Callers must keep the result out of
|
|
530
|
-
* agent, MCP, A2A, logs, persistence, and extension/tool surfaces.
|
|
530
|
+
* agent, MCP, A2A, logs, persistence, and extension/tool surfaces. The one
|
|
531
|
+
* exception is the provider's own remote MCP endpoint, which may receive it as
|
|
532
|
+
* a per-request bearer (`mcp-client/workspace-connection-servers.ts`); it is
|
|
533
|
+
* still never stored on the server config or shown to the agent.
|
|
531
534
|
*/
|
|
532
535
|
export declare function resolveProviderApiOAuthAccessToken(args: {
|
|
533
536
|
provider: ProviderApiId;
|
|
@@ -1722,7 +1722,10 @@ function providerAccessErrorGuidance(config, status) {
|
|
|
1722
1722
|
/**
|
|
1723
1723
|
* Resolve a provider OAuth token for a trusted server-side integration bridge
|
|
1724
1724
|
* such as a CRM adapter or Google Picker. Callers must keep the result out of
|
|
1725
|
-
* agent, MCP, A2A, logs, persistence, and extension/tool surfaces.
|
|
1725
|
+
* agent, MCP, A2A, logs, persistence, and extension/tool surfaces. The one
|
|
1726
|
+
* exception is the provider's own remote MCP endpoint, which may receive it as
|
|
1727
|
+
* a per-request bearer (`mcp-client/workspace-connection-servers.ts`); it is
|
|
1728
|
+
* still never stored on the server config or shown to the agent.
|
|
1726
1729
|
*/
|
|
1727
1730
|
export async function resolveProviderApiOAuthAccessToken(args, runtime) {
|
|
1728
1731
|
await assertProviderAllowedAsync(args.provider, runtime);
|
|
@@ -44,17 +44,26 @@ const READ_ONLY_POST_RULES = [
|
|
|
44
44
|
// extract jobs make no such promise.
|
|
45
45
|
body: (body) => isDryRunQueryJob(body.configuration),
|
|
46
46
|
},
|
|
47
|
+
// HubSpot paths carry `v3`/`v4` or a date-based version such as `2026-09`,
|
|
48
|
+
// which HubSpot accepts on either side of the API name
|
|
49
|
+
// (`/crm/objects/2026-09/...` and `/crm/2026-09/objects/...`).
|
|
47
50
|
{
|
|
48
51
|
provider: "hubspot",
|
|
49
52
|
basePath: "",
|
|
50
53
|
hostSuffixes: ["hubapi.com"],
|
|
51
|
-
path: /^\/crm\/v3\/
|
|
54
|
+
path: /^\/crm\/(?:(?:v3|\d{4}-\d{2})\/objects|objects\/\d{4}-\d{2})\/[^/]+\/(?:search|batch\/read)$/,
|
|
52
55
|
},
|
|
53
56
|
{
|
|
54
57
|
provider: "hubspot",
|
|
55
58
|
basePath: "",
|
|
56
59
|
hostSuffixes: ["hubapi.com"],
|
|
57
|
-
path: /^\/crm\/
|
|
60
|
+
path: /^\/crm\/(?:(?:v3|\d{4}-\d{2})\/properties|properties\/\d{4}-\d{2})\/[^/]+\/batch\/read$/,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
provider: "hubspot",
|
|
64
|
+
basePath: "",
|
|
65
|
+
hostSuffixes: ["hubapi.com"],
|
|
66
|
+
path: /^\/crm\/(?:(?:v[34]|\d{4}-\d{2})\/associations|associations\/\d{4}-\d{2})\/[^/]+\/[^/]+\/batch\/read$/,
|
|
58
67
|
},
|
|
59
68
|
{
|
|
60
69
|
provider: "gong",
|
|
@@ -49,6 +49,7 @@ export declare function handleUploadResource(event: any): Promise<import("./stor
|
|
|
49
49
|
error: string;
|
|
50
50
|
storageSetupRequired?: undefined;
|
|
51
51
|
} | {
|
|
52
|
+
error?: undefined;
|
|
52
53
|
id: string;
|
|
53
54
|
path: string;
|
|
54
55
|
owner: string;
|
|
@@ -63,7 +64,6 @@ export declare function handleUploadResource(event: any): Promise<import("./stor
|
|
|
63
64
|
runId: string | null;
|
|
64
65
|
expiresAt: number | null;
|
|
65
66
|
metadata: string | null;
|
|
66
|
-
error?: undefined;
|
|
67
67
|
url: string;
|
|
68
68
|
provider: string;
|
|
69
69
|
storageSetupRequired?: undefined;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -55,18 +55,18 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
|
|
|
55
55
|
errorCode: "secret_managed_elsewhere";
|
|
56
56
|
managedBy: SecretManagedBy;
|
|
57
57
|
} | {
|
|
58
|
-
errorCode?: undefined;
|
|
59
|
-
error: string;
|
|
60
58
|
ok?: undefined;
|
|
59
|
+
error: string;
|
|
60
|
+
errorCode?: undefined;
|
|
61
61
|
status?: undefined;
|
|
62
62
|
} | {
|
|
63
|
+
ok?: undefined;
|
|
63
64
|
error: string;
|
|
64
65
|
errorCode: string;
|
|
65
|
-
ok?: undefined;
|
|
66
66
|
status?: undefined;
|
|
67
67
|
} | {
|
|
68
|
-
errorCode?: undefined;
|
|
69
68
|
error?: undefined;
|
|
69
|
+
errorCode?: undefined;
|
|
70
70
|
ok: boolean;
|
|
71
71
|
status: string;
|
|
72
72
|
} | {
|
|
@@ -289,6 +289,8 @@ export const ALWAYS_ON_CORE_ACTIONS = new Set([
|
|
|
289
289
|
"call-mcp-tool",
|
|
290
290
|
// Connection setup UI needs the workspace prerequisite even in minimal apps.
|
|
291
291
|
"get-managed-mcp-oauth-readiness",
|
|
292
|
+
// Any app calling a provider API needs to see which scopes its connection holds.
|
|
293
|
+
"list-workspace-connection-scopes",
|
|
292
294
|
"get-agentkit-capabilities",
|
|
293
295
|
"get-hosted-harness-config",
|
|
294
296
|
"set-hosted-harness-enabled",
|
|
@@ -437,6 +439,10 @@ export function coreActionLoaderEntries() {
|
|
|
437
439
|
"list-workspace-user-groups",
|
|
438
440
|
() => import("../workspace-connections/actions/list-workspace-user-groups.js"),
|
|
439
441
|
],
|
|
442
|
+
[
|
|
443
|
+
"list-workspace-connection-scopes",
|
|
444
|
+
() => import("../workspace-connections/actions/list-workspace-connection-scopes.js"),
|
|
445
|
+
],
|
|
440
446
|
[
|
|
441
447
|
"upsert-workspace-user-group",
|
|
442
448
|
() => import("../workspace-connections/actions/upsert-workspace-user-group.js"),
|
|
@@ -1,11 +1,67 @@
|
|
|
1
1
|
import { CLAIMED_BACKGROUND_WORKER_FAILED_ERROR_EVENT, finalizeClaimedBackgroundRunFailure, readBackgroundRunClaim, recordRunDiagnostic, RUN_DIAG_STAGE, } from "../../agent/run-store.js";
|
|
2
|
+
function safeDiagnosticToken(value) {
|
|
3
|
+
return typeof value === "string" && /^[A-Za-z0-9_]{1,64}$/.test(value)
|
|
4
|
+
? value
|
|
5
|
+
: undefined;
|
|
6
|
+
}
|
|
7
|
+
function readFailureMessage(err) {
|
|
8
|
+
try {
|
|
9
|
+
return {
|
|
10
|
+
message: err instanceof Error ? err.message : String(err),
|
|
11
|
+
readable: true,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return { message: "unreadable thrown value", readable: false };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function routeFailureEvidence(err, message, messageReadable) {
|
|
19
|
+
try {
|
|
20
|
+
const error = err;
|
|
21
|
+
const cause = error?.cause;
|
|
22
|
+
const errorName = safeDiagnosticToken(error?.name) ??
|
|
23
|
+
(err instanceof Error ? "unknown" : "NonError");
|
|
24
|
+
const errorCode = safeDiagnosticToken(error?.code) ?? safeDiagnosticToken(cause?.code);
|
|
25
|
+
const causeName = safeDiagnosticToken(cause?.name);
|
|
26
|
+
const errorMessage = /^Background worker returned HTTP ([45]\d\d)(?: code=([A-Za-z0-9_]{1,64}))?$/.exec(message);
|
|
27
|
+
const evidence = {
|
|
28
|
+
format: "route_failure_v1",
|
|
29
|
+
...(!messageReadable ? { errorMetadata: "unreadable" } : {}),
|
|
30
|
+
errorName,
|
|
31
|
+
...(errorCode
|
|
32
|
+
? { errorCode }
|
|
33
|
+
: errorMessage?.[2]
|
|
34
|
+
? { errorCode: errorMessage[2] }
|
|
35
|
+
: {}),
|
|
36
|
+
...(errorMessage?.[1] ? { httpStatus: errorMessage[1] } : {}),
|
|
37
|
+
...(causeName ? { causeName } : {}),
|
|
38
|
+
};
|
|
39
|
+
const tokens = [
|
|
40
|
+
...(evidence.errorMetadata
|
|
41
|
+
? [`errorMetadata=${evidence.errorMetadata}`]
|
|
42
|
+
: []),
|
|
43
|
+
...(evidence.errorName ? [`errorName=${evidence.errorName}`] : []),
|
|
44
|
+
...(evidence.httpStatus ? [`httpStatus=${evidence.httpStatus}`] : []),
|
|
45
|
+
...(evidence.errorCode ? [`errorCode=${evidence.errorCode}`] : []),
|
|
46
|
+
...(evidence.causeName ? [`causeName=${evidence.causeName}`] : []),
|
|
47
|
+
];
|
|
48
|
+
return { detail: `${tokens.join(" ")} failure=${message}`, evidence };
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return {
|
|
52
|
+
detail: `errorMetadata=unreadable failure=${message}`,
|
|
53
|
+
evidence: { format: "route_failure_v1", errorMetadata: "unreadable" },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
2
57
|
export async function finalizeClaimedAgentChatProcessRunFailure(runId, err, deps = {}) {
|
|
3
58
|
const readClaim = deps.readBackgroundRunClaim ?? readBackgroundRunClaim;
|
|
4
59
|
const record = deps.recordRunDiagnostic ?? recordRunDiagnostic;
|
|
5
60
|
const finalizeFailure = deps.finalizeClaimedBackgroundRunFailure ??
|
|
6
61
|
finalizeClaimedBackgroundRunFailure;
|
|
7
|
-
const message
|
|
8
|
-
|
|
62
|
+
const { message, readable } = readFailureMessage(err);
|
|
63
|
+
const diagnostic = routeFailureEvidence(err, message, readable);
|
|
64
|
+
await record(runId, RUN_DIAG_STAGE.routeThrew, diagnostic.detail, diagnostic.evidence).catch(() => { });
|
|
9
65
|
const claim = await readClaim(runId);
|
|
10
66
|
if (claim?.status !== "running" ||
|
|
11
67
|
claim.dispatchMode !== "background-processing") {
|
|
@@ -54,21 +54,21 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
|
|
|
54
54
|
error: string;
|
|
55
55
|
}>;
|
|
56
56
|
export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
57
|
-
error: string;
|
|
58
57
|
errorCode?: undefined;
|
|
59
58
|
code?: undefined;
|
|
59
|
+
error: string;
|
|
60
60
|
} | {
|
|
61
|
+
code?: undefined;
|
|
61
62
|
error: string;
|
|
62
63
|
errorCode: string;
|
|
63
|
-
code?: undefined;
|
|
64
64
|
} | {
|
|
65
65
|
errorCode?: undefined;
|
|
66
66
|
error: string;
|
|
67
67
|
code: ProviderKeyCheckCode;
|
|
68
68
|
} | {
|
|
69
|
-
error?: undefined;
|
|
70
69
|
errorCode?: undefined;
|
|
71
70
|
code?: undefined;
|
|
71
|
+
error?: undefined;
|
|
72
72
|
ok: boolean;
|
|
73
73
|
key: string;
|
|
74
74
|
baseUrlKey?: string | undefined;
|
|
@@ -85,6 +85,7 @@ export declare function isWorkspaceProviderOAuthFlowValid(input: {
|
|
|
85
85
|
}): boolean;
|
|
86
86
|
export declare function canConnectWorkspaceProviderOAuth(orgId: string | null | undefined, role: string | null | undefined): boolean;
|
|
87
87
|
export declare function scopedOAuthAccountId(provider: GenericWorkspaceOAuthProvider, owner: string, accountId: string): string;
|
|
88
|
+
export declare function tokenScopes(tokens: Record<string, unknown>, fallback: readonly string[]): string[];
|
|
88
89
|
export declare function mergeWorkspaceOAuthValues(existing: readonly string[], incoming: readonly string[]): string[];
|
|
89
90
|
export declare function resolveSalesforceOAuthLoginUrl(environment: string | undefined): string | null;
|
|
90
91
|
export declare function salesforceOAuthEndpoint(loginUrl: string, phase: "authorize" | "token"): string;
|
|
@@ -1202,9 +1202,17 @@ async function fetchBoundedProviderJsonValue(url, init, providerLabel) {
|
|
|
1202
1202
|
return { response, body: {} };
|
|
1203
1203
|
}
|
|
1204
1204
|
}
|
|
1205
|
-
function tokenScopes(tokens, fallback) {
|
|
1205
|
+
export function tokenScopes(tokens, fallback) {
|
|
1206
1206
|
const scope = text(tokens.scope);
|
|
1207
|
-
|
|
1207
|
+
if (scope)
|
|
1208
|
+
return scope.split(/[ ,]+/).filter(Boolean);
|
|
1209
|
+
// HubSpot's token endpoint returns the granted scopes as a `scopes` array.
|
|
1210
|
+
if (Array.isArray(tokens.scopes)) {
|
|
1211
|
+
const scopes = tokens.scopes.filter((value) => typeof value === "string" && value !== "");
|
|
1212
|
+
if (scopes.length)
|
|
1213
|
+
return scopes;
|
|
1214
|
+
}
|
|
1215
|
+
return [...fallback];
|
|
1208
1216
|
}
|
|
1209
1217
|
export function mergeWorkspaceOAuthValues(existing, incoming) {
|
|
1210
1218
|
return [...new Set([...existing, ...incoming])];
|
|
@@ -93,3 +93,16 @@ cross-source joins, multi-page provider sweeps, and heavy analysis scripts;
|
|
|
93
93
|
keep quick scripts in the default foreground mode. Agents should continue
|
|
94
94
|
other work between polls, and on `failed`/`timed_out` split the computation or
|
|
95
95
|
persist intermediate progress with `workspaceWrite` and re-run.
|
|
96
|
+
|
|
97
|
+
## HubSpot API versions
|
|
98
|
+
|
|
99
|
+
Write new HubSpot code against a date-based API version (2026-09 or later),
|
|
100
|
+
for example `POST /crm/objects/2026-09/contacts`, not `/crm/v3/...`. Only the
|
|
101
|
+
date-based versions apply the portal's required-property rules to API writes:
|
|
102
|
+
a create that leaves out a property the portal's create form requires, or a
|
|
103
|
+
stage change missing a conditionally required property, is rejected with a
|
|
104
|
+
400, while the same request on `/crm/v3/` succeeds. HubSpot also stops
|
|
105
|
+
supporting v1-v3 after September 2027. Moving existing write code to a dated
|
|
106
|
+
version changes its behavior, because writes that pass today can start failing
|
|
107
|
+
validation, so migrate one app at a time and surface those 400s to the user.
|
|
108
|
+
Reads behave the same on either version.
|
|
@@ -93,3 +93,16 @@ cross-source joins, multi-page provider sweeps, and heavy analysis scripts;
|
|
|
93
93
|
keep quick scripts in the default foreground mode. Agents should continue
|
|
94
94
|
other work between polls, and on `failed`/`timed_out` split the computation or
|
|
95
95
|
persist intermediate progress with `workspaceWrite` and re-run.
|
|
96
|
+
|
|
97
|
+
## HubSpot API versions
|
|
98
|
+
|
|
99
|
+
Write new HubSpot code against a date-based API version (2026-09 or later),
|
|
100
|
+
for example `POST /crm/objects/2026-09/contacts`, not `/crm/v3/...`. Only the
|
|
101
|
+
date-based versions apply the portal's required-property rules to API writes:
|
|
102
|
+
a create that leaves out a property the portal's create form requires, or a
|
|
103
|
+
stage change missing a conditionally required property, is rejected with a
|
|
104
|
+
400, while the same request on `/crm/v3/` succeeds. HubSpot also stops
|
|
105
|
+
supporting v1-v3 after September 2027. Moving existing write code to a dated
|
|
106
|
+
version changes its behavior, because writes that pass today can start failing
|
|
107
|
+
validation, so migrate one app at a time and surface those 400s to the user.
|
|
108
|
+
Reads behave the same on either version.
|
|
@@ -21,6 +21,10 @@ not judged by ledgers, receipts, or checker output, so don't produce them.
|
|
|
21
21
|
|
|
22
22
|
## The contract
|
|
23
23
|
|
|
24
|
+
The detailed Slack reaction and reply rules are in
|
|
25
|
+
[slack-reaction-replies.md](references/slack-reaction-replies.md); read it before
|
|
26
|
+
marking, replying to, or closing any Slack report.
|
|
27
|
+
|
|
24
28
|
Slack reactions on a report's root message mean exactly this:
|
|
25
29
|
|
|
26
30
|
| Mark | Meaning | When to add |
|
|
@@ -43,7 +47,8 @@ might need to take back. Every 👀 you add ends the run with a reply, plus
|
|
|
43
47
|
either ✅ or 🎫, or a fix PR that is still open and lists the report (its
|
|
44
48
|
merge adds the ✅). A 👀 with no follow-up is the most common complaint about this workflow.
|
|
45
49
|
|
|
46
|
-
Every claimed report gets **one** reply in its thread per outcome.
|
|
50
|
+
Every claimed report gets **one** reply in its thread per outcome. The one exception is
|
|
51
|
+
the merged `✅` close-out after an in-review reply, which gets no second reply. People
|
|
47
52
|
have pushed back on replies that were long, technical, condescending, vague
|
|
48
53
|
about who does what next, or that handed them work. Each reply must be:
|
|
49
54
|
|
|
@@ -261,9 +266,10 @@ apart from Steve's own 👀.
|
|
|
261
266
|
- **Prove it.** The check has to fail with the fix's source changes put
|
|
262
267
|
back to `main` and pass with them. A check that passes without your fix
|
|
263
268
|
doesn't test the bug: write one that does. Tests that read source text
|
|
264
|
-
never count. For a purely visual fix,
|
|
265
|
-
|
|
266
|
-
|
|
269
|
+
never count. For a purely visual fix, before and after screenshots are
|
|
270
|
+
evidence for a person to inspect, not automated proof. Before merging, a
|
|
271
|
+
human must open both images and confirm they show the reported change. Put
|
|
272
|
+
the evidence under the report in the PR's `Reports` section.
|
|
267
273
|
- **Two misses, then stop guessing.** If two attempts don't turn the check
|
|
268
274
|
green, stop editing and capture the real failure first (stack, logs, the
|
|
269
275
|
reporter's actual data). If that doesn't settle it within about 30
|