@zackbart/connecta 0.37.0 → 0.38.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/CHANGELOG.md +80 -0
- package/README.md +2 -2
- package/bin/connecta.mjs +1 -39
- package/bin/version.mjs +1 -1
- package/dist/access-tokens.js +2 -4
- package/dist/agent-identity.js +1 -1
- package/dist/auth/clerk-sdk/generated.js +2 -1
- package/dist/auth/cloudflare-access.d.ts +3 -1
- package/dist/auth/cloudflare-access.js +22 -11
- package/dist/auth/downstream-oauth.js +195 -270
- package/dist/auth/downstream-revocation.js +1 -1
- package/dist/auth/oauth-grant.js +11 -0
- package/dist/auth/oauth-token-response.js +1 -1
- package/dist/auth/vercel-agent.js +2 -1
- package/dist/auth-elicitation.js +2 -2
- package/dist/branding.d.ts +1 -15
- package/dist/branding.js +2 -2
- package/dist/bytes.js +42 -0
- package/dist/call-admission-context.js +2 -5
- package/dist/call-admission.js +5 -0
- package/dist/call-recovery.js +0 -3
- package/dist/catalog-cache.js +26 -7
- package/dist/catalog-fingerprint.js +2 -18
- package/dist/catalog-revision.js +9 -0
- package/dist/catalog-service.js +51 -20
- package/dist/config-defaults.d.ts +1 -0
- package/dist/config-defaults.js +1 -0
- package/dist/config-schema.d.ts +1 -1
- package/dist/config-schema.js +6 -2
- package/dist/config.d.ts +41 -14
- package/dist/config.js +21 -71
- package/dist/connector-caller.js +1 -1
- package/dist/connectors/api-connector.js +4 -3
- package/dist/connectors/guarded-fetch.d.ts +0 -6
- package/dist/connectors/guarded-fetch.js +1 -11
- package/dist/connectors/remote-mcp.js +93 -69
- package/dist/connectors/resource-uri.js +0 -4
- package/dist/credentials.js +3 -0
- package/dist/d1.d.ts +0 -89
- package/dist/d1.js +0 -34
- package/dist/downstream-input.js +2 -2
- package/dist/execute.js +161 -116
- package/dist/executor-result.js +2 -1
- package/dist/executors/quickjs-runtime.js +2 -25
- package/dist/executors/quickjs.js +1 -1
- package/dist/guest-runtime.js +5 -3
- package/dist/guest-types.d.ts +5 -5
- package/dist/http/client.js +1 -1
- package/dist/http/errors.js +2 -2
- package/dist/http/json-schema.js +1 -1
- package/dist/http/node-transport.js +0 -1
- package/dist/http/oauth.js +1 -1
- package/dist/http/paging.js +6 -9
- package/dist/http/provider.js +1 -1
- package/dist/http/safety.js +1 -1
- package/dist/http/services.js +1 -8
- package/dist/http/tools.js +1 -7
- package/dist/http/vendor.js +7 -7
- package/dist/identity.js +2 -6
- package/dist/index.js +1 -2
- package/dist/invocation-auth.js +2 -1
- package/dist/invocation.js +8 -2
- package/dist/meta-tools.js +27 -27
- package/dist/native-tools.js +2 -1
- package/dist/oauth-handoff.js +2 -2
- package/dist/operation-vocabulary.js +1 -1
- package/dist/operator-record.d.ts +8 -2
- package/dist/operator-record.js +18 -50
- package/dist/operator-ui/contract.d.ts +4 -2
- package/dist/operator-ui/generated.js +3 -3
- package/dist/operator-ui/model.d.ts +7 -2
- package/dist/program-writes.js +3 -8
- package/dist/provider-call.js +0 -7
- package/dist/provider.d.ts +1 -1
- package/dist/providers/_shared/google/kit.js +1 -6
- package/dist/providers/_shared/google/service-account.js +1 -3
- package/dist/providers/_shared/google/workspace.d.ts +1 -1
- package/dist/providers/_shared/guide.js +3 -0
- package/dist/providers/_shared/json.js +12 -0
- package/dist/providers/_shared/rest/compact-index.js +1 -1
- package/dist/providers/_shared/rest/kit.js +1 -3
- package/dist/providers/_shared/rest/operation-index.js +1 -3
- package/dist/providers/_shared/rest/value-safety.js +26 -28
- package/dist/providers/breeze/api.js +2 -7
- package/dist/providers/breeze/index.js +4 -2
- package/dist/providers/breeze/tools.js +3 -4
- package/dist/providers/ccb/api.js +1 -6
- package/dist/providers/ccb/index.js +2 -1
- package/dist/providers/ccb/tools.js +1 -6
- package/dist/providers/cloudflare/api.js +2 -2
- package/dist/providers/cloudflare/index.js +2 -1
- package/dist/providers/cloudflare/safety.js +3 -3
- package/dist/providers/docs/tools.js +2 -10
- package/dist/providers/drive/tools.js +12 -25
- package/dist/providers/forms/tools.js +1 -9
- package/dist/providers/gmail/tools.js +5 -21
- package/dist/providers/overflow/api.js +1 -3
- package/dist/providers/overflow/index.js +2 -1
- package/dist/providers/overflow/tools.js +3 -7
- package/dist/providers/planning-center/api.js +2 -1
- package/dist/providers/planning-center/lib/constants.d.ts +1 -1
- package/dist/providers/planning-center/lib/json-api.js +1 -9
- package/dist/providers/planning-center/tools.js +2 -1
- package/dist/providers/sheets/tools.js +1 -9
- package/dist/providers/slides/tools.js +4 -13
- package/dist/providers/stripe/index.js +2 -1
- package/dist/providers/stripe/safety.js +2 -2
- package/dist/providers/tithely/api.js +2 -7
- package/dist/providers/tithely/index.js +3 -2
- package/dist/providers/tithely/tools.js +7 -5
- package/dist/providers/vercel/api.js +1 -6
- package/dist/providers/vercel/lib/pin.js +1 -1
- package/dist/providers/vercel/safety.js +1 -1
- package/dist/providers/vercel/tools.js +2 -1
- package/dist/redaction-marker.js +2 -2
- package/dist/registry.d.ts +4 -1
- package/dist/registry.js +35 -22
- package/dist/request-principal.js +15 -2
- package/dist/request-state.js +2 -2
- package/dist/routes/access-tokens.js +1 -1
- package/dist/routes/activity-disclosure.js +1 -1
- package/dist/routes/connect.js +2 -2
- package/dist/routes/credentials.js +1 -1
- package/dist/routes/dispatch.js +10 -0
- package/dist/routes/mcp.js +23 -21
- package/dist/routes/oauth-management.js +1 -1
- package/dist/routes/operator.js +53 -7
- package/dist/routes/shared.d.ts +8 -8
- package/dist/routes/shared.js +22 -15
- package/dist/routes/ui-config.js +6 -6
- package/dist/routes/ui-data.js +2 -2
- package/dist/routes/ui.js +9 -4
- package/dist/runtime/call-admission.js +1 -1
- package/dist/runtime/call.js +1 -1
- package/dist/runtime/settlement.js +1 -1
- package/dist/runtime/shared-read.js +2 -15
- package/dist/sent-secrets.d.ts +14 -6
- package/dist/sent-secrets.js +231 -85
- package/dist/server.js +4 -4
- package/dist/skills.js +8 -35
- package/dist/sqlite.d.ts +0 -19
- package/dist/sqlite.js +2 -83
- package/dist/storage/keys.js +29 -124
- package/dist/storage/sql-native.js +14 -111
- package/dist/storage/sql.d.ts +1 -24
- package/dist/storage/sql.js +1 -12
- package/dist/tool-error.js +4 -0
- package/dist/types.d.ts +4 -3
- package/dist/ui.js +3 -0
- package/dist/url-safety.js +0 -4
- package/dist/usage-guide.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker.js +1 -1
- package/documentation/README.md +6 -42
- package/documentation/architecture.md +190 -507
- package/documentation/auth.md +172 -58
- package/documentation/code-mode.md +98 -66
- package/documentation/deploying.md +19 -40
- package/documentation/integrating.md +8 -19
- package/documentation/meta-tools.md +23 -6
- package/documentation/migration-0.33.md +5 -5
- package/documentation/migration-0.34.md +2 -4
- package/documentation/migration-retired-layouts.md +74 -0
- package/documentation/operator-tests.md +19 -119
- package/documentation/operator-ui.md +46 -8
- package/documentation/provider-auth-migration.md +4 -10
- package/documentation/provider-migration-0.29.md +4 -15
- package/examples/worker/AGENTS.md +4 -6
- package/examples/worker/README.md +20 -115
- package/guides/connecting-agents.md +7 -30
- package/guides/how-it-works.md +2 -2
- package/guides/safety-and-trust.md +4 -1
- package/package.json +19 -19
- package/templates/node/README.md +9 -26
- package/templates/node/package.json +1 -1
- package/dist/auth/oauth-v2-migration.js +0 -135
- package/dist/provider-call-facts.d.ts +0 -115
- package/dist/provider-call.d.ts +0 -112
- package/dist/storage/d1-copy.js +0 -255
- package/dist/storage/sql-schema.d.ts +0 -6
- package/examples/worker/kv-to-d1.wrangler.jsonc +0 -26
- package/examples/worker/scripts/copy-kv-to-d1.mjs +0 -162
package/dist/d1.d.ts
CHANGED
|
@@ -38,93 +38,4 @@ export declare function d1Storage(db: D1DatabaseBinding): KVStorage;
|
|
|
38
38
|
* write prunes a bounded batch of rows older than `retentionDays`.
|
|
39
39
|
*/
|
|
40
40
|
export declare function d1ActivityStore(db: D1DatabaseBinding, options?: D1ActivityOptions): ActivityStore;
|
|
41
|
-
/**
|
|
42
|
-
* The part of a Workers KV binding `copyKvToD1` reads. Structural, like
|
|
43
|
-
* `D1DatabaseBinding`; a Worker's `KVNamespace` satisfies it.
|
|
44
|
-
*/
|
|
45
|
-
export interface KVNamespaceBinding {
|
|
46
|
-
list(options?: {
|
|
47
|
-
limit?: number;
|
|
48
|
-
cursor?: string | null;
|
|
49
|
-
}): Promise<{
|
|
50
|
-
keys: readonly {
|
|
51
|
-
name: string;
|
|
52
|
-
expiration?: number;
|
|
53
|
-
}[];
|
|
54
|
-
list_complete: boolean;
|
|
55
|
-
cursor?: string;
|
|
56
|
-
}>;
|
|
57
|
-
get(key: string, type: "text"): Promise<string | null>;
|
|
58
|
-
}
|
|
59
|
-
export interface KvToD1CopyOptions {
|
|
60
|
-
/** The source KV namespace id. Resume tokens are bound to this identity. */
|
|
61
|
-
source: string;
|
|
62
|
-
/** Resume against the same source and database within seven days. */
|
|
63
|
-
cursor?: string;
|
|
64
|
-
/** Explicit families whose conflicting D1 rows the operator judged stale. */
|
|
65
|
-
overwriteFamilies?: readonly string[];
|
|
66
|
-
/** Compare value hashes and absolute expiries without copying entries. */
|
|
67
|
-
verify?: boolean;
|
|
68
|
-
/** Override the cutover guard only after assessing stale KV state. */
|
|
69
|
-
allowStale?: boolean;
|
|
70
|
-
/** Keys read per call. Default 500; use a smaller budget for large rows. */
|
|
71
|
-
maxKeys?: number;
|
|
72
|
-
}
|
|
73
|
-
/** What a copy did with one family's keys. */
|
|
74
|
-
export interface KvToD1Counts {
|
|
75
|
-
/** Written where D1 held no live entry. */
|
|
76
|
-
copied: number;
|
|
77
|
-
/** D1 already held the same value. */
|
|
78
|
-
unchanged: number;
|
|
79
|
-
/** D1 held a different value or expiry and kept it. */
|
|
80
|
-
conflicts: number;
|
|
81
|
-
/** D1 held a different value or expiry, replaced under `overwriteFamilies`. */
|
|
82
|
-
overwritten: number;
|
|
83
|
-
/** Expired or deleted in Workers KV before it could be read. */
|
|
84
|
-
expired: number;
|
|
85
|
-
/** A key/value/row D1 cannot hold, left in Workers KV. */
|
|
86
|
-
invalid: number;
|
|
87
|
-
/** Exact value hash and expiry match during a verification pass. */
|
|
88
|
-
verified: number;
|
|
89
|
-
/** Missing or different value/expiry during a verification pass. */
|
|
90
|
-
mismatches: number;
|
|
91
|
-
}
|
|
92
|
-
export interface KvToD1CopyResult {
|
|
93
|
-
/** True once the whole namespace has been read. */
|
|
94
|
-
done: boolean;
|
|
95
|
-
/**
|
|
96
|
-
* Pass back as `options.cursor` to continue; absent when `done`. A random
|
|
97
|
-
* token: the Workers KV cursor it stands for stays in D1, because that
|
|
98
|
-
* cursor can spell the last key listed.
|
|
99
|
-
*/
|
|
100
|
-
cursor?: string;
|
|
101
|
-
/**
|
|
102
|
-
* Counts by key family (`src/storage/keys.ts`), plus `connector-owned` and
|
|
103
|
-
* `unclassified`. Never a key or a value.
|
|
104
|
-
*/
|
|
105
|
-
families: Record<string, KvToD1Counts>;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* A copy that stopped. The message is fixed wording that names a family at
|
|
109
|
-
* most, never a key or value, and the binding's own error is not attached:
|
|
110
|
-
* KV and D1 errors can quote either. Entries before `cursor` are copied;
|
|
111
|
-
* rerunning from it is safe while the maintenance window still holds.
|
|
112
|
-
*/
|
|
113
|
-
export declare class KvToD1CopyError extends Error {
|
|
114
|
-
/** Resume point; absent means start over, which is also safe. */
|
|
115
|
-
readonly cursor: string | undefined;
|
|
116
|
-
readonly name = "KvToD1CopyError";
|
|
117
|
-
constructor(message: string,
|
|
118
|
-
/** Resume point; absent means start over, which is also safe. */
|
|
119
|
-
cursor: string | undefined);
|
|
120
|
-
}
|
|
121
|
-
/** Mark cutover before reopening traffic. The marker stays in D1 permanently. */
|
|
122
|
-
export declare function markKvToD1Live(db: D1DatabaseBinding, source: string): Promise<void>;
|
|
123
|
-
/**
|
|
124
|
-
* Copy live KV entries verbatim while all writers and traffic are stopped.
|
|
125
|
-
* A live D1 row is kept unless its family is explicitly allowed to overwrite.
|
|
126
|
-
* `verify` reads hashes and absolute expiries without changing copied entries.
|
|
127
|
-
* Results contain counts only. Resume tokens are source-bound atomic claims.
|
|
128
|
-
*/
|
|
129
|
-
export declare function copyKvToD1(kv: KVNamespaceBinding, db: D1DatabaseBinding, options: KvToD1CopyOptions): Promise<KvToD1CopyResult>;
|
|
130
41
|
export {};
|
package/dist/d1.js
CHANGED
|
@@ -3,12 +3,8 @@
|
|
|
3
3
|
// One D1 database holds everything: `d1Storage(db)` is the deployment's
|
|
4
4
|
// `KVStorage`, and `d1ActivityStore(db)` its activity history. Both create
|
|
5
5
|
// their tables on first use, so binding the database is the whole setup.
|
|
6
|
-
// `copyKvToD1` moves a 0.28 deployment's Workers KV state into it once.
|
|
7
|
-
import { runEdge } from "./runtime/run.js";
|
|
8
6
|
import { d1Driver } from "./storage/d1-driver.js";
|
|
9
|
-
import { copyKvToD1Effect, markKvToD1LiveEffect } from "./storage/d1-copy.js";
|
|
10
7
|
import { sqlActivityStore, sqlStorage } from "./storage/sql.js";
|
|
11
|
-
import { keepErrorName } from "./redaction-identity.js";
|
|
12
8
|
/**
|
|
13
9
|
* `KVStorage` over a D1 database, with the atomic `compareAndSet` every
|
|
14
10
|
* subsystem relies on. The `connecta_kv` table is created on first use; a
|
|
@@ -25,33 +21,3 @@ export function d1Storage(db) {
|
|
|
25
21
|
export function d1ActivityStore(db, options) {
|
|
26
22
|
return sqlActivityStore(d1Driver(db), "d1", options);
|
|
27
23
|
}
|
|
28
|
-
/**
|
|
29
|
-
* A copy that stopped. The message is fixed wording that names a family at
|
|
30
|
-
* most, never a key or value, and the binding's own error is not attached:
|
|
31
|
-
* KV and D1 errors can quote either. Entries before `cursor` are copied;
|
|
32
|
-
* rerunning from it is safe while the maintenance window still holds.
|
|
33
|
-
*/
|
|
34
|
-
export class KvToD1CopyError extends Error {
|
|
35
|
-
cursor;
|
|
36
|
-
name = "KvToD1CopyError";
|
|
37
|
-
constructor(message,
|
|
38
|
-
/** Resume point; absent means start over, which is also safe. */
|
|
39
|
-
cursor) {
|
|
40
|
-
super(message);
|
|
41
|
-
this.cursor = cursor;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
keepErrorName(KvToD1CopyError, "KvToD1CopyError");
|
|
45
|
-
/** Mark cutover before reopening traffic. The marker stays in D1 permanently. */
|
|
46
|
-
export function markKvToD1Live(db, source) {
|
|
47
|
-
return runEdge(markKvToD1LiveEffect(db, source));
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Copy live KV entries verbatim while all writers and traffic are stopped.
|
|
51
|
-
* A live D1 row is kept unless its family is explicitly allowed to overwrite.
|
|
52
|
-
* `verify` reads hashes and absolute expiries without changing copied entries.
|
|
53
|
-
* Results contain counts only. Resume tokens are source-bound atomic claims.
|
|
54
|
-
*/
|
|
55
|
-
export function copyKvToD1(kv, db, options) {
|
|
56
|
-
return runEdge(copyKvToD1Effect(kv, db, options));
|
|
57
|
-
}
|
package/dist/downstream-input.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { toolError } from "./tool-error.js";
|
|
1
2
|
import { RequestScope, requestOwner } from "./runtime/request-scope.js";
|
|
2
3
|
import { Effect } from "effect";
|
|
3
4
|
import { upwardStep } from "./upward.js";
|
|
@@ -129,8 +130,7 @@ function failure(code, message, write = false) {
|
|
|
129
130
|
writeOutcome: "unknown",
|
|
130
131
|
}
|
|
131
132
|
: { code, message, retryable: false };
|
|
132
|
-
|
|
133
|
-
return { content: [{ type: "text", text: JSON.stringify(structuredContent) }], structuredContent, isError: true };
|
|
133
|
+
return toolError(error, { ok: false });
|
|
134
134
|
}
|
|
135
135
|
/** MCP-only continuation coordination. No downstream prompt enters operator records. */
|
|
136
136
|
export class DownstreamElicitation {
|
package/dist/execute.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { authCall, authInvoke, authMethod } from "./auth/native.js";
|
|
1
|
+
import { authCall, authFlow, authInvoke, authMethod } from "./auth/native.js";
|
|
2
2
|
import { nativeRecovery } from "./native-recovery.js";
|
|
3
3
|
import { GUEST_API_DECLARATION } from "./usage-guide.js";
|
|
4
4
|
import { bindMcpClient } from "./mcp-client-context.js";
|
|
@@ -18,10 +18,11 @@ import { guestPrelude, programError, wrapGuestProgram } from "./guest-runtime.js
|
|
|
18
18
|
import { EXECUTE_OUTPUT } from "./meta-output.js";
|
|
19
19
|
import { normalizeProgramSource } from "./program-source.js";
|
|
20
20
|
import { readResource } from "./resource-read.js";
|
|
21
|
-
import {
|
|
21
|
+
import { redactAgentOutput, sentSecretsForRequest } from "./sent-secrets.js";
|
|
22
22
|
import { normalizeTimeoutMs } from "./timeout.js";
|
|
23
23
|
import { fromSignal, runEdge, withDeadlineEffect } from "./runtime/run.js";
|
|
24
24
|
import { closeScope } from "./runtime/connector-scope.js";
|
|
25
|
+
import { RequestScope, requestOwner } from "./runtime/request-scope.js";
|
|
25
26
|
import { executorProgram } from "./runtime/executor.js";
|
|
26
27
|
import { connectorGuide, connectorGuideRequired, connectorSkillName, hasConnectorGuides, SkillsRegistry, } from "./skills.js";
|
|
27
28
|
/** Keep one model-written program from amplifying into an unbounded fan-out. */
|
|
@@ -174,13 +175,15 @@ export class EmitCollector {
|
|
|
174
175
|
maxBytes;
|
|
175
176
|
maxBlocks;
|
|
176
177
|
diagnostics;
|
|
178
|
+
maxResultChars;
|
|
177
179
|
blocks = [];
|
|
178
180
|
bytes = 0;
|
|
179
181
|
textChars = 0;
|
|
180
|
-
constructor(maxBytes, maxBlocks, diagnostics) {
|
|
182
|
+
constructor(maxBytes, maxBlocks, diagnostics, maxResultChars = MAX_EXECUTE_RESULT_CHARS) {
|
|
181
183
|
this.maxBytes = maxBytes;
|
|
182
184
|
this.maxBlocks = maxBlocks;
|
|
183
185
|
this.diagnostics = diagnostics;
|
|
186
|
+
this.maxResultChars = maxResultChars;
|
|
184
187
|
}
|
|
185
188
|
accept(raw) {
|
|
186
189
|
this.acceptNative([requireEmittedBlock(raw)]);
|
|
@@ -204,8 +207,8 @@ export class EmitCollector {
|
|
|
204
207
|
// the transport budget, just like images and audio.
|
|
205
208
|
if (block.type === "resource" && "text" in block.resource)
|
|
206
209
|
textChars += serialized.length;
|
|
207
|
-
if (textChars >
|
|
208
|
-
throw guestFailure("result_too_large",
|
|
210
|
+
if (textChars > this.maxResultChars - 512) {
|
|
211
|
+
throw guestFailure("result_too_large", `Emitted text shares the ${this.maxResultChars.toLocaleString("en-US")}-character program result limit. Reduce the text before emitting it.`);
|
|
209
212
|
}
|
|
210
213
|
count++;
|
|
211
214
|
bytes += size;
|
|
@@ -469,8 +472,20 @@ function sandboxProvider(registry, baseUrl, activity, limits, requestScope = {})
|
|
|
469
472
|
...(limits.dispatchController ? { dispatchSignal: limits.dispatchController.signal } : {}),
|
|
470
473
|
unwrapResult: true,
|
|
471
474
|
readOnly: limits.readOnly,
|
|
472
|
-
processResult:
|
|
473
|
-
|
|
475
|
+
processResult: authMethod((value, resolved, secrets, format, raw) => Effect.gen(function* () {
|
|
476
|
+
// Dispatch succeeded before presentation began. Cancellation of paging
|
|
477
|
+
// cannot turn this completed write into an unknown or failed write.
|
|
478
|
+
sending.settle?.("ok");
|
|
479
|
+
const page = (data, valueFormat, wireBytes) => authCall(pageProgramResult, [
|
|
480
|
+
registry,
|
|
481
|
+
baseUrl,
|
|
482
|
+
resolved,
|
|
483
|
+
data,
|
|
484
|
+
valueFormat,
|
|
485
|
+
secrets,
|
|
486
|
+
requestScope,
|
|
487
|
+
wireBytes,
|
|
488
|
+
]);
|
|
474
489
|
const envelope = resolved.connector.kind === "mcp" && raw !== null && typeof raw === "object"
|
|
475
490
|
? raw
|
|
476
491
|
: undefined;
|
|
@@ -485,12 +500,12 @@ function sandboxProvider(registry, baseUrl, activity, limits, requestScope = {})
|
|
|
485
500
|
// the structured value synchronously; no native metadata is visited.
|
|
486
501
|
if (dataKey !== undefined &&
|
|
487
502
|
diagnosticsEncoder.encode(JSON.stringify(value)).byteLength > PROGRAM_RESULT_INLINE_BYTES) {
|
|
488
|
-
return page(value, format, PROGRAM_RESULT_WIRE_BYTES - 1024);
|
|
503
|
+
return yield* page(value, format, PROGRAM_RESULT_WIRE_BYTES - 1024);
|
|
489
504
|
}
|
|
490
505
|
const content = envelope?.content;
|
|
491
506
|
if (!Array.isArray(content) ||
|
|
492
507
|
!content.some((block) => block && ["image", "audio", "resource", "resource_link"].includes(block.type))) {
|
|
493
|
-
return transportResult(
|
|
508
|
+
return transportResult(yield* page(value, format));
|
|
494
509
|
}
|
|
495
510
|
const unavailablePresentation = () => ({
|
|
496
511
|
format: "paged",
|
|
@@ -516,7 +531,7 @@ function sandboxProvider(registry, baseUrl, activity, limits, requestScope = {})
|
|
|
516
531
|
catch (error) {
|
|
517
532
|
if (!(error instanceof NativePresentationLimit))
|
|
518
533
|
throw error;
|
|
519
|
-
const result = dataKey === undefined ? undefined : transportResult(
|
|
534
|
+
const result = dataKey === undefined ? undefined : transportResult(yield* page(value, format));
|
|
520
535
|
const notice = unavailablePresentation();
|
|
521
536
|
return result ? { value: result, native: { value: notice } } : notice;
|
|
522
537
|
}
|
|
@@ -525,8 +540,9 @@ function sandboxProvider(registry, baseUrl, activity, limits, requestScope = {})
|
|
|
525
540
|
// original bytes even if the structured-data stash pauses.
|
|
526
541
|
const resultPending = dataKey === undefined ? undefined : page(value, format, PROGRAM_RESULT_WIRE_BYTES - 1024);
|
|
527
542
|
const nativePending = page(snapshot, "json");
|
|
528
|
-
const result =
|
|
529
|
-
|
|
543
|
+
const [result, native] = yield* Effect.all([resultPending ?? Effect.succeed(undefined), nativePending], {
|
|
544
|
+
concurrency: "unbounded",
|
|
545
|
+
});
|
|
530
546
|
let valueResult;
|
|
531
547
|
if (native.format === "paged") {
|
|
532
548
|
valueResult = result ? transportResult(result) : undefined;
|
|
@@ -548,7 +564,7 @@ function sandboxProvider(registry, baseUrl, activity, limits, requestScope = {})
|
|
|
548
564
|
...(valueResult ? { value: valueResult } : {}),
|
|
549
565
|
native: { ref, value: transportResult(native), dataKey },
|
|
550
566
|
};
|
|
551
|
-
},
|
|
567
|
+
})),
|
|
552
568
|
beforeWrite: (target) => Effect.sync(() => {
|
|
553
569
|
if (programWrites?.isClosed) {
|
|
554
570
|
return {
|
|
@@ -736,8 +752,10 @@ function sandboxProvider(registry, baseUrl, activity, limits, requestScope = {})
|
|
|
736
752
|
}),
|
|
737
753
|
skill: (name, _options, utilitySignal) => Effect.tryPromise({
|
|
738
754
|
try: async () => {
|
|
739
|
-
|
|
740
|
-
|
|
755
|
+
// Accept the top-level skills tool's { name } shape too: models copy it into programs.
|
|
756
|
+
const skillName = name && typeof name === "object" ? name.name : name;
|
|
757
|
+
if (typeof skillName !== "string")
|
|
758
|
+
throw guestFailure("invalid_args", 'Use connecta.skill("usage") or connecta.skill("connector:<id>") with an exact skill name; the skills tool lists names.');
|
|
741
759
|
const skills = new SkillsRegistry(registry, baseUrl, {
|
|
742
760
|
requestScope,
|
|
743
761
|
requestSignal: utilitySignal ?? hostAccessSignal,
|
|
@@ -749,7 +767,7 @@ function sandboxProvider(registry, baseUrl, activity, limits, requestScope = {})
|
|
|
749
767
|
probeTimeoutMs: limits.probeTimeoutMs,
|
|
750
768
|
defer: limits.defer,
|
|
751
769
|
});
|
|
752
|
-
return { name, format: "text", text: await skills.text(
|
|
770
|
+
return { name: skillName, format: "text", text: await skills.text(skillName) };
|
|
753
771
|
},
|
|
754
772
|
catch: (err) => err instanceof ConnectorCallError ? guestFailure(err.code, err.message, err.code === "unavailable") : err,
|
|
755
773
|
}),
|
|
@@ -1030,12 +1048,11 @@ export function createExecuteTool(registry, baseUrl, executor, logger, activity,
|
|
|
1030
1048
|
logger,
|
|
1031
1049
|
};
|
|
1032
1050
|
const hostCallTimeoutMs = resolveBudget(config.hostCallTimeoutMs, EXECUTE_HOST_CALL_TIMEOUT_MS);
|
|
1033
|
-
const
|
|
1051
|
+
const maxResultChars = resolveBudget(config.maxResultChars, MAX_EXECUTE_RESULT_CHARS);
|
|
1052
|
+
const play = (program, diagnosticsRequested, callerSignal, requestScope, hostCalls, programWrites) => Effect.suspend(() => {
|
|
1034
1053
|
const sentSecrets = sentSecretsForRequest(requestScope);
|
|
1035
1054
|
const diagnostics = diagnosticsRequested ? new ExecuteDiagnostics() : undefined;
|
|
1036
|
-
const emitted = new EmitCollector(resolveBudget(config.maxEmittedBytes, EXECUTE_MAX_EMITTED_BYTES), resolveBudget(config.maxEmittedBlocks, EXECUTE_MAX_EMITTED_BLOCKS), diagnostics);
|
|
1037
|
-
const hostCalls = { attempted: 0, admitted: 0, succeeded: 0, failed: 0 };
|
|
1038
|
-
const programWrites = new ProgramWrites();
|
|
1055
|
+
const emitted = new EmitCollector(resolveBudget(config.maxEmittedBytes, EXECUTE_MAX_EMITTED_BYTES), resolveBudget(config.maxEmittedBlocks, EXECUTE_MAX_EMITTED_BLOCKS), diagnostics, maxResultChars);
|
|
1039
1056
|
const resultDependencies = [];
|
|
1040
1057
|
const dispatchController = new AbortController();
|
|
1041
1058
|
const terminal = Deferred.makeUnsafe();
|
|
@@ -1116,21 +1133,34 @@ export function createExecuteTool(registry, baseUrl, executor, logger, activity,
|
|
|
1116
1133
|
}).pipe(Effect.map((outcome) => sentSecrets.redact(outcome)), Effect.mapError((error) => sentSecrets.redact(error))), signal, { watchdog, terminal: Deferred.await(terminal) }).pipe(Effect.ensuring(Effect.suspend(() => {
|
|
1117
1134
|
programWrites.close();
|
|
1118
1135
|
dispatchController.abort();
|
|
1119
|
-
|
|
1136
|
+
// Finalizers are masked by default. The request must be able
|
|
1137
|
+
// to stop this wait as well as the invocations being drained.
|
|
1138
|
+
return programWrites.drain().pipe(Effect.interruptible);
|
|
1120
1139
|
}))));
|
|
1121
1140
|
});
|
|
1122
1141
|
const reported = {
|
|
1123
1142
|
emitted,
|
|
1124
1143
|
diagnostics,
|
|
1125
1144
|
program,
|
|
1126
|
-
|
|
1145
|
+
// Emitted text shares the return cap; a follow-up page run gets all of it.
|
|
1146
|
+
guardResult: (value) => authCall(guardProgramReturn, [
|
|
1147
|
+
value,
|
|
1148
|
+
registry,
|
|
1149
|
+
baseUrl,
|
|
1150
|
+
[...new Map(resultDependencies.map((dependency) => [JSON.stringify(dependency), dependency])).values()],
|
|
1151
|
+
sentSecrets,
|
|
1152
|
+
logger,
|
|
1153
|
+
maxResultChars - emitted.textChars,
|
|
1154
|
+
programWrites.hasSucceeded,
|
|
1155
|
+
maxResultChars,
|
|
1156
|
+
]),
|
|
1127
1157
|
};
|
|
1128
1158
|
const exited = Effect.exit(Effect.scoped(run)).pipe(Effect.flatMap((exit) =>
|
|
1129
1159
|
// Releasing a QuickJS lease ends its child and rejects execute() with
|
|
1130
1160
|
// the retained log prefix. Give that report one timer turn, just as
|
|
1131
1161
|
// cancellation does in awaitExecutor; never wait on a Worker isolate.
|
|
1132
1162
|
budgetFailure ? Effect.sleep(Duration.millis(1)).pipe(Effect.as(exit)) : Effect.succeed(exit)));
|
|
1133
|
-
return Effect.
|
|
1163
|
+
return Effect.flatMap(exited, (exit) => {
|
|
1134
1164
|
// A synchronous fire-and-forget burst can also settle its executor in
|
|
1135
1165
|
// this turn. The host's terminal refusal always wins over that value.
|
|
1136
1166
|
if (budgetFailure instanceof HostCallBudgetExceeded) {
|
|
@@ -1145,36 +1175,47 @@ export function createExecuteTool(registry, baseUrl, executor, logger, activity,
|
|
|
1145
1175
|
if (Exit.isFailure(exit)) {
|
|
1146
1176
|
return Effect.succeed(failedRun(redactAgentOutput(sentSecrets, Cause.squash(exit.cause)), logger, reported));
|
|
1147
1177
|
}
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
//
|
|
1151
|
-
const
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
return response;
|
|
1158
|
-
}).pipe(Effect.map((result) => redactAgentOutput(sentSecrets, result)));
|
|
1178
|
+
// The executor lease is already released, but presenting its return
|
|
1179
|
+
// still belongs to the caller. Compose the registered stash program
|
|
1180
|
+
// here so cancellation interrupts storage waits and their continuations.
|
|
1181
|
+
const cancelled = new ExecutorAdmissionError("executor_cancelled", "Execution was cancelled during result processing.");
|
|
1182
|
+
return withDeadlineEffect(() => finishedRun(redactAgentOutput(sentSecrets, exit.value), reported), {
|
|
1183
|
+
...(callerSignal ? { signal: callerSignal } : {}),
|
|
1184
|
+
timeoutError: cancelled,
|
|
1185
|
+
}).pipe(Effect.catch((error) => Effect.succeed(failedRun(callerSignal?.aborted ? cancelled : error, logger, reported))));
|
|
1186
|
+
});
|
|
1159
1187
|
});
|
|
1160
|
-
return
|
|
1161
|
-
|
|
1188
|
+
return authMethod(({ code, diagnostics }, options = {}) => Effect.suspend(() => {
|
|
1189
|
+
const requestScope = config.requestScope ?? {};
|
|
1190
|
+
const sentSecrets = sentSecretsForRequest(requestScope);
|
|
1191
|
+
const owner = requestOwner(requestScope);
|
|
1192
|
+
if (!owner.open)
|
|
1193
|
+
return Effect.fail(owner.controller.signal.reason);
|
|
1194
|
+
const hostCalls = { attempted: 0, admitted: 0, succeeded: 0, failed: 0 };
|
|
1195
|
+
const programWrites = new ProgramWrites();
|
|
1196
|
+
const response = Effect.suspend(() => {
|
|
1162
1197
|
// A code-unit count above the cap is already too large in UTF-8. Check
|
|
1163
1198
|
// that first so a huge direct-call string is never encoded in full.
|
|
1164
1199
|
if (code.length > EXECUTE_MAX_CODE_BYTES ||
|
|
1165
1200
|
new TextEncoder().encode(code).byteLength > EXECUTE_MAX_CODE_BYTES) {
|
|
1166
1201
|
const message = `execute_code code exceeds the ${EXECUTE_MAX_CODE_BYTES}-byte UTF-8 limit.`;
|
|
1167
|
-
|
|
1168
|
-
response.structuredContent = {
|
|
1169
|
-
...response.structuredContent,
|
|
1170
|
-
hostCalls: { attempted: 0, admitted: 0, succeeded: 0, failed: 0 },
|
|
1171
|
-
};
|
|
1172
|
-
response.content[0].text = JSON.stringify(response.structuredContent);
|
|
1173
|
-
return Effect.succeed(response);
|
|
1202
|
+
return Effect.succeed(failureResponse(message, { code: { code: "invalid_args", message, retryable: false } }));
|
|
1174
1203
|
}
|
|
1175
|
-
return
|
|
1176
|
-
})
|
|
1177
|
-
|
|
1204
|
+
return play(normalizeProgramSource(code), diagnostics, options.signal, requestScope, hostCalls, programWrites);
|
|
1205
|
+
});
|
|
1206
|
+
return response.pipe(Effect.provideService(RequestScope, owner), Effect.map((unfinished) => {
|
|
1207
|
+
// Every response, including intake refusals, crosses accounting and
|
|
1208
|
+
// exactly one envelope check at this operation boundary.
|
|
1209
|
+
const result = redactAgentOutput(sentSecrets, programWrites.finish(unfinished));
|
|
1210
|
+
// Calls abandoned by the guest are failed when the run cancels them.
|
|
1211
|
+
// Connecta attaches its own integers after the envelope check.
|
|
1212
|
+
const counts = { ...hostCalls, failed: hostCalls.attempted - hostCalls.succeeded };
|
|
1213
|
+
result.structuredContent = { ...result.structuredContent, hostCalls: counts };
|
|
1214
|
+
if (result.content[0]?.type === "text")
|
|
1215
|
+
result.content[0].text = JSON.stringify(result.structuredContent);
|
|
1216
|
+
return result;
|
|
1217
|
+
}), Effect.catchDefect(Effect.fail), Effect.mapError((error) => redactAgentOutput(sentSecrets, error)));
|
|
1218
|
+
}));
|
|
1178
1219
|
}
|
|
1179
1220
|
/** An execution that never produced an ExecuteResult, as the model sees it. */
|
|
1180
1221
|
function failedRun(err, logger, { emitted, diagnostics, program }) {
|
|
@@ -1215,81 +1256,83 @@ function failedRun(err, logger, { emitted, diagnostics, program }) {
|
|
|
1215
1256
|
});
|
|
1216
1257
|
}
|
|
1217
1258
|
/** The response for an ExecuteResult: the program's error or its value. */
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1259
|
+
function finishedRun(outcome, { emitted, diagnostics, program, guardResult }) {
|
|
1260
|
+
return authFlow(function* () {
|
|
1261
|
+
if (outcome === null || typeof outcome !== "object" || Array.isArray(outcome)) {
|
|
1262
|
+
return failureResponse("Executor failed: expected an ExecuteResult object.", {
|
|
1263
|
+
emitted,
|
|
1264
|
+
diagnostics,
|
|
1265
|
+
code: "executor_failed",
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
const logs = executeLogs(outcome.logs);
|
|
1269
|
+
if (outcome.error !== undefined && typeof outcome.error !== "string") {
|
|
1270
|
+
return failureResponse("Executor failed: ExecuteResult.error must be a string.", {
|
|
1271
|
+
logs,
|
|
1272
|
+
emitted,
|
|
1273
|
+
diagnostics,
|
|
1274
|
+
code: "executor_failed",
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
if (outcome.error !== undefined) {
|
|
1278
|
+
const failure = outcome.failure?.call;
|
|
1279
|
+
if (outcome.failure?.timeout) {
|
|
1280
|
+
const { elapsedMs, deadlineMs } = outcome.failure.timeout;
|
|
1281
|
+
const message = `Operation "execute_code" timed out during sandbox after ${elapsedMs}ms (effective deadline ${deadlineMs}ms).`;
|
|
1282
|
+
return failureResponse(message, {
|
|
1283
|
+
logs,
|
|
1284
|
+
emitted,
|
|
1285
|
+
diagnostics,
|
|
1286
|
+
code: {
|
|
1287
|
+
code: "timeout",
|
|
1288
|
+
message,
|
|
1289
|
+
retryable: false,
|
|
1290
|
+
details: { operation: "execute_code", stage: "sandbox", elapsedMs, deadlineMs },
|
|
1291
|
+
},
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
return failureResponse(failure?.message ?? outcome.error, {
|
|
1295
|
+
logs,
|
|
1296
|
+
emitted,
|
|
1297
|
+
diagnostics,
|
|
1298
|
+
code: failure ??
|
|
1299
|
+
programError({
|
|
1300
|
+
name: outcome.failure?.name ?? /^(SyntaxError|ReferenceError|TypeError|RangeError):/.exec(outcome.error)?.[1],
|
|
1301
|
+
message: outcome.error || "Execution failed without an error message.",
|
|
1302
|
+
...(outcome.failure?.line !== undefined ? { line: outcome.failure.line - 1 } : {}),
|
|
1303
|
+
}, program),
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
// A result crossing back as a host BigInt (or otherwise unserializable
|
|
1307
|
+
// value) makes JSON.stringify throw — keep that inside the structured
|
|
1308
|
+
// error path so captured logs survive instead of a raw SDK 500.
|
|
1309
|
+
let result;
|
|
1310
|
+
try {
|
|
1311
|
+
result = yield* guardResult(outcome.result);
|
|
1312
|
+
}
|
|
1313
|
+
catch (err) {
|
|
1314
|
+
const message = `Error: result is not JSON-serializable: ${msg(err)}`;
|
|
1240
1315
|
return failureResponse(message, {
|
|
1241
1316
|
logs,
|
|
1242
1317
|
emitted,
|
|
1243
1318
|
diagnostics,
|
|
1244
|
-
code:
|
|
1245
|
-
code: "timeout",
|
|
1246
|
-
message,
|
|
1247
|
-
retryable: false,
|
|
1248
|
-
details: { operation: "execute_code", stage: "sandbox", elapsedMs, deadlineMs },
|
|
1249
|
-
},
|
|
1319
|
+
code: "executor_failed",
|
|
1250
1320
|
});
|
|
1251
1321
|
}
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
emitted,
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
programError({
|
|
1258
|
-
name: outcome.failure?.name ?? /^(SyntaxError|ReferenceError|TypeError|RangeError):/.exec(outcome.error)?.[1],
|
|
1259
|
-
message: outcome.error || "Execution failed without an error message.",
|
|
1260
|
-
...(outcome.failure?.line !== undefined ? { line: outcome.failure.line - 1 } : {}),
|
|
1261
|
-
}, program),
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1264
|
-
// A result crossing back as a host BigInt (or otherwise unserializable
|
|
1265
|
-
// value) makes JSON.stringify throw — keep that inside the structured
|
|
1266
|
-
// error path so captured logs survive instead of a raw SDK 500.
|
|
1267
|
-
let result;
|
|
1268
|
-
try {
|
|
1269
|
-
result = await guardResult(outcome.result, MAX_EXECUTE_RESULT_CHARS - emitted.textChars);
|
|
1270
|
-
}
|
|
1271
|
-
catch (err) {
|
|
1272
|
-
const message = `Error: result is not JSON-serializable: ${msg(err)}`;
|
|
1273
|
-
return failureResponse(message, {
|
|
1274
|
-
logs,
|
|
1275
|
-
emitted,
|
|
1276
|
-
diagnostics,
|
|
1277
|
-
code: "executor_failed",
|
|
1322
|
+
const response = jsonResult({
|
|
1323
|
+
result,
|
|
1324
|
+
...(emitted.blocks.length > 0 ? { emitted: emitted.blocks.length } : {}),
|
|
1325
|
+
...(logs ? { logs } : {}),
|
|
1326
|
+
...(diagnostics ? { diagnostics: diagnostics.finish() } : {}),
|
|
1278
1327
|
});
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1328
|
+
if (emitted.blocks.length > 0) {
|
|
1329
|
+
// Emitted image/audio blocks are valid MCP content that ToolResult's
|
|
1330
|
+
// text-only typing does not model — the same acknowledged gap
|
|
1331
|
+
// guardContent lives with for downstream block passthrough.
|
|
1332
|
+
response.content.push(...emitted.blocks);
|
|
1333
|
+
}
|
|
1334
|
+
return response;
|
|
1285
1335
|
});
|
|
1286
|
-
if (emitted.blocks.length > 0) {
|
|
1287
|
-
// Emitted image/audio blocks are valid MCP content that ToolResult's
|
|
1288
|
-
// text-only typing does not model — the same acknowledged gap
|
|
1289
|
-
// guardContent lives with for downstream block passthrough.
|
|
1290
|
-
response.content.push(...emitted.blocks);
|
|
1291
|
-
}
|
|
1292
|
-
return response;
|
|
1293
1336
|
}
|
|
1294
1337
|
function executeLogs(value) {
|
|
1295
1338
|
return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "string")
|
|
@@ -1345,7 +1388,7 @@ function connectorInventory(connectors) {
|
|
|
1345
1388
|
return `${prefix}${shown.join(", ")}.`;
|
|
1346
1389
|
return `${prefix}${shown.join(", ")}${shown.length > 0 ? "; " : ""}+${omitted} more.`;
|
|
1347
1390
|
}
|
|
1348
|
-
const executeDescription = (emitBudgets, hostLimits, connectorGuides, connectors, maxWrites, readOnly, native = false) => `${native ? `Call tools directly; combine work here using their program addresses. ${readOnly ? "Read-only endpoint: writes are omitted and refused." : "Writable endpoint: programs may read and write; the client approves."}` : readOnly ? "One known read: call_tool. Everything else: execute_code. Read-only endpoint: search and describe omit write tools, and every write call is refused." : "One known read: call_tool. One known write: call_destructive_tool. Everything else: execute_code. Writable endpoint: programs may read and write; the client approves."} Limits: ${hostLimits.maxHostCalls} host calls, ${readOnly ? "" : `${maxWrites} writes, `}${hostLimits.hostCallTimeoutMs / 1_000}s/host call.
|
|
1391
|
+
const executeDescription = (emitBudgets, hostLimits, connectorGuides, connectors, maxWrites, readOnly, native = false) => `${native ? `Call tools directly; combine work here using their program addresses. ${readOnly ? "Read-only endpoint: writes are omitted and refused." : "Writable endpoint: programs may read and write; the client approves."}` : readOnly ? "One known read: call_tool. Everything else: execute_code. Read-only endpoint: search and describe omit write tools, and every write call is refused." : "One known read: call_tool. One known write: call_destructive_tool. Everything else: execute_code. Writable endpoint: programs may read and write; the client approves."} Limits: ${hostLimits.maxHostCalls} host calls, ${readOnly ? "" : `${maxWrites} writes, `}${hostLimits.callTimeoutMs === hostLimits.hostCallTimeoutMs ? `${hostLimits.callTimeoutMs / 1_000}s/host call` : `${hostLimits.callTimeoutMs / 1_000}s/call (${hostLimits.hostCallTimeoutMs / 1_000}s result/skill/read)`}.
|
|
1349
1392
|
${connectorInventory(connectors)}
|
|
1350
1393
|
|
|
1351
1394
|
Use async () => { ... }, no arguments. No portable ambient capabilities. API:
|
|
@@ -1356,7 +1399,7 @@ ${GUEST_API_DECLARATION}
|
|
|
1356
1399
|
\`\`\`
|
|
1357
1400
|
Search: {tools}, catalogErrors. JSON schemas default; compact text. Calls: {data, format:"json"|"text"}; >1 MiB: paged handle. Oversized returns: resultId/nextAction. connecta.result pages; UTF-8 byte offsets. allSettled keeps typed errors; host budget_exceeded ends the run.
|
|
1358
1401
|
|
|
1359
|
-
Never repeat writes for output. emit(result) or emit(block) from result.content forwards MCP blocks. Authored: text/base64 image/audio; no await. Caps: ${emitBudgets.maxBlocks} blocks/${emitBudgets.maxBytes} bytes. Text shares result cap.
|
|
1402
|
+
Never repeat writes for output. emit(result) or emit(block) from result.content forwards MCP blocks. Authored: text/base64 image/audio; no await. Caps: ${emitBudgets.maxBlocks} blocks/${emitBudgets.maxBytes} bytes. Text shares result cap. connecta.skill("usage"): repair${connectorGuides ? ", guide handling" : ""}; connecta.skill("investigate"): workflow.`;
|
|
1360
1403
|
// Module scope, like the other five meta-tool inputs: its JSON Schema is
|
|
1361
1404
|
// derived once per process. Budgets and connectors vary by deployment and
|
|
1362
1405
|
// view, so they live in the description, never here.
|
|
@@ -1394,12 +1437,14 @@ export function registerExecuteTool(server, registry, ctx) {
|
|
|
1394
1437
|
defer: ctx.defer,
|
|
1395
1438
|
readOnly: ctx.readOnly,
|
|
1396
1439
|
maxWrites,
|
|
1440
|
+
maxResultChars: ctx.maxResultChars,
|
|
1397
1441
|
requestScope: ctx.requestScope,
|
|
1398
1442
|
});
|
|
1399
1443
|
server.registerTool("execute_code", {
|
|
1400
1444
|
description: executeDescription(emitBudgets, {
|
|
1401
1445
|
...hostLimits,
|
|
1402
|
-
|
|
1446
|
+
// connecta.call falls back to calls.defaultTimeoutMs; result, skill and read always use hostCallTimeoutMs.
|
|
1447
|
+
callTimeoutMs: normalizeTimeoutMs(ctx.defaultToolTimeoutMs) ?? hostLimits.hostCallTimeoutMs,
|
|
1403
1448
|
}, hasConnectorGuides(connectors), connectors, maxWrites, ctx.readOnly === true, ctx.native === true),
|
|
1404
1449
|
inputSchema: EXECUTE_INPUT,
|
|
1405
1450
|
outputSchema: EXECUTE_OUTPUT,
|
package/dist/executor-result.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { CONFIG_DEFAULTS } from "./config-defaults.js";
|
|
1
2
|
import { msg } from "./errors.js";
|
|
2
3
|
/** ~6k tokens. Sandbox code should filter data down before returning. */
|
|
3
|
-
export const MAX_EXECUTE_RESULT_CHARS =
|
|
4
|
+
export const MAX_EXECUTE_RESULT_CHARS = CONFIG_DEFAULTS.execute.maxResultChars;
|
|
4
5
|
export const MAX_EXECUTE_LOG_CHARS = 4_000;
|
|
5
6
|
export function serializeResultText(value) {
|
|
6
7
|
const serialized = JSON.stringify(value);
|