@theokit/sdk 3.2.0 → 3.2.2
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 +26 -0
- package/dist/a2a/index.cjs +36 -14
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.js +36 -14
- package/dist/a2a/index.js.map +1 -1
- package/dist/cron.cjs +36 -14
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.js +36 -14
- package/dist/cron.js.map +1 -1
- package/dist/eval.cjs +36 -29
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +36 -29
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +45 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +45 -15
- package/dist/index.js.map +1 -1
- package/dist/sandbox/index.cjs +8 -9
- package/dist/sandbox/index.cjs.map +1 -1
- package/dist/sandbox/index.js +8 -9
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/types.d.cts +0 -1
- package/dist/sandbox/types.d.ts +0 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.2.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7f57c5a: Security (#55) — a delegated subagent now inherits the parent's code-registered plugins (e.g. `PermissionPlugin`), so its inner tool calls run under the SAME argument-level permission gate. Previously the child `Agent.create` received only apiKey/model/tools, so a parent that denied `shell` with a matching-arg rule did not stop a subagent it granted `shell` to — arg-level gating silently stopped at the delegation boundary.
|
|
8
|
+
- f81ac79: Fix (#58) — a run cancelled between tool iterations now reports `RunStatus: "cancelled"` instead of `"finished"`, so a caller can distinguish a cancellation from a clean completion. Previously the between-iteration abort break left the default `"finished"` status.
|
|
9
|
+
- 57cfcc8: Fix (#58) — `JobQueue.cancel()` on a running job that ignores its `AbortSignal` (never settles) previously leaked its concurrency slot, deadlocking a `maxConcurrency`-bounded queue. Cancel now frees the slot immediately; `#release` is idempotent so the job's eventual settle is a no-op (no double-free).
|
|
10
|
+
- bd06140: Fix (#65) — the `transform_llm_output` plugin hook now rewrites the FINAL user-visible / streamed assistant text, and fires on text-only terminal turns. Previously it ran only in the tool-call branch and folded only into internal message history, so a plugin could not scrub what the caller actually received. The transform is now applied once, up front, and flows into the emitted step, `finalText`/`result`, and message history alike.
|
|
11
|
+
|
|
12
|
+
## 3.2.1
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- a283dd4: Security (#54) — harden child-process env scrubbing.
|
|
17
|
+
|
|
18
|
+
- The `inherit-scrubbed` denylist now also drops the highest-signal VALUE-embedded-secret conventions: connection strings that carry `user:password@` (`DATABASE_URL`, `REDIS_URL`, `MONGODB_URI`, `DB_URL`, …), plus `DSN`, `WEBHOOK`, `COOKIE`, and `CONNECTION_STRING`. Generic non-secret URLs (`PUBLIC_BASE_URL`, `API_URL`, `PGHOST`) are deliberately preserved. A denylist still cannot catch every value-embedded secret — policy `core` (allowlist) remains the fail-closed mode for untrusted children.
|
|
19
|
+
- Removed dead `validateCommand` / `SHELL_METACHARACTERS` from the sandbox base — a never-invoked "guard" that provided a false sense of protection.
|
|
20
|
+
- Added an end-to-end test proving `LocalSandbox.execute` scrubs secret-like host env vars from the real child process.
|
|
21
|
+
|
|
22
|
+
- 826bca0: Security (#56) — close two residual cross-tenant active-recall cache leaks found by adversarial review.
|
|
23
|
+
|
|
24
|
+
- `@theokit/sdk-memory` (publishable) called `cache.get`/`cache.set` with no tenant context, so two callers with the same query text but different identity shared a cached recall — a cross-tenant leak for every consumer of the package. The cache read/write are now keyed by the `{namespace, userId, scope}` tenant tuple (the primitive already supported it).
|
|
25
|
+
- In `@theokit/sdk` the production caller hardcoded `namespace: "default"` and dropped `memoryContext.tenantId`, so two tenants sharing a `userId` collided on one cache entry. The caller now threads `memoryContext.tenantId` into the tenant partition (`namespace`). `sessionId` is intentionally not a key dimension — recall is cross-session by design.
|
|
26
|
+
|
|
27
|
+
- 7bcc872: Security/correctness (#59) — the HTTP MCP body read (`response.json()`) was outside the abort try/catch, so a server that returned headers then stalled the body surfaced a raw `DOMException(TimeoutError)` instead of the typed `NetworkError{code:"mcp_timeout"}`. The request was still bounded (no hang), but the typed-timeout contract now holds across both the header and body phases.
|
|
28
|
+
|
|
3
29
|
## 3.2.0
|
|
4
30
|
|
|
5
31
|
### Minor Changes
|
package/dist/a2a/index.cjs
CHANGED
|
@@ -4743,7 +4743,14 @@ var init_env_policy = __esm({
|
|
|
4743
4743
|
/[_-]PWD/i,
|
|
4744
4744
|
/CREDENTIAL/i,
|
|
4745
4745
|
/PRIVATE/i,
|
|
4746
|
-
/_AUTH/i
|
|
4746
|
+
/_AUTH/i,
|
|
4747
|
+
// #54-a — value-embedded-secret conventions (no generic `*_URL` — see keep-list test).
|
|
4748
|
+
/DSN/i,
|
|
4749
|
+
/WEBHOOK/i,
|
|
4750
|
+
/COOKIE/i,
|
|
4751
|
+
/CONNECTION[_-]?STRING/i,
|
|
4752
|
+
// Known DB / message-broker connection-string vars (carry `user:pass@`).
|
|
4753
|
+
/(?:^|[_-])(?:DATABASE|DB|REDIS|MONGO(?:DB)?|POSTGRES(?:QL)?|MYSQL|MARIADB|AMQP|RABBITMQ|CLICKHOUSE|ELASTIC(?:SEARCH)?|CASSANDRA|COUCHDB|MEMCACHED|NATS|KAFKA)[_-]?(?:URL|URI|DSN|CONNECTION)/i
|
|
4747
4754
|
];
|
|
4748
4755
|
CORE_VARS = [
|
|
4749
4756
|
"PATH",
|
|
@@ -9498,7 +9505,10 @@ async function runAgentLoop(inputs) {
|
|
|
9498
9505
|
}
|
|
9499
9506
|
budget.consume();
|
|
9500
9507
|
inputs.budgetTracker?.nextIteration?.();
|
|
9501
|
-
if (inputs.signal?.aborted === true)
|
|
9508
|
+
if (inputs.signal?.aborted === true) {
|
|
9509
|
+
ctx.finalStatus = "cancelled";
|
|
9510
|
+
break;
|
|
9511
|
+
}
|
|
9502
9512
|
}
|
|
9503
9513
|
if (lastTurnDecision === "continue" && budget.shouldContinue() === false) {
|
|
9504
9514
|
ctx.stoppedAtIterationLimit = true;
|
|
@@ -9683,15 +9693,15 @@ async function guardAndTransformToolResults(inputs, raw, ctx) {
|
|
|
9683
9693
|
}
|
|
9684
9694
|
async function continueOrTerminate(inputs, ctx, llmOutput) {
|
|
9685
9695
|
if (llmOutput.errored) return "error";
|
|
9686
|
-
|
|
9687
|
-
|
|
9696
|
+
const tCtx = { agentId: inputs.agentId, runId: inputs.runId };
|
|
9697
|
+
const text = llmOutput.text.length > 0 ? await transformLlmOutputText(inputs, llmOutput.text, tCtx) : llmOutput.text;
|
|
9698
|
+
if (text.length > 0) {
|
|
9699
|
+
await emitAssistantTextStep(inputs, ctx, text);
|
|
9688
9700
|
}
|
|
9689
9701
|
if (llmOutput.stopReason !== "tool_use" || llmOutput.toolCalls.length === 0) {
|
|
9690
9702
|
return finishOrReflect(inputs, ctx, llmOutput);
|
|
9691
9703
|
}
|
|
9692
|
-
|
|
9693
|
-
const outText = await transformLlmOutputText(inputs, llmOutput.text, tCtx);
|
|
9694
|
-
ctx.messages.push(buildAssistantTurn(outText, llmOutput.toolCalls));
|
|
9704
|
+
ctx.messages.push(buildAssistantTurn(text, llmOutput.toolCalls));
|
|
9695
9705
|
const rawResults = await dispatchTools(
|
|
9696
9706
|
// SE12 — forward a read-only text projection of the transcript-so-far to tool
|
|
9697
9707
|
// handlers via `ctx.messages` (consumed by defineSubAgent's messageFilter).
|
|
@@ -13015,7 +13025,12 @@ var init_client = __esm({
|
|
|
13015
13025
|
code: "mcp_http_error"
|
|
13016
13026
|
});
|
|
13017
13027
|
}
|
|
13018
|
-
|
|
13028
|
+
try {
|
|
13029
|
+
return await response.json();
|
|
13030
|
+
} catch (cause) {
|
|
13031
|
+
if (isAbortLike(cause)) throw mcpTimeoutError(this.name, timeoutMs);
|
|
13032
|
+
throw cause;
|
|
13033
|
+
}
|
|
13019
13034
|
}
|
|
13020
13035
|
};
|
|
13021
13036
|
}
|
|
@@ -13255,9 +13270,11 @@ function declarativeSubagentTools(agentOptions, parentTools) {
|
|
|
13255
13270
|
return subAgentToolsFromDefinitions(agents2, parentTools);
|
|
13256
13271
|
}
|
|
13257
13272
|
function bindParentCredentials(tools, agentOptions) {
|
|
13273
|
+
const parentPlugins = Array.isArray(agentOptions.plugins) ? agentOptions.plugins : void 0;
|
|
13258
13274
|
const credentials = {
|
|
13259
13275
|
...agentOptions.apiKey !== void 0 ? { apiKey: agentOptions.apiKey } : {},
|
|
13260
|
-
...typeof agentOptions.model === "object" ? { model: agentOptions.model } : {}
|
|
13276
|
+
...typeof agentOptions.model === "object" ? { model: agentOptions.model } : {},
|
|
13277
|
+
...parentPlugins !== void 0 ? { plugins: parentPlugins } : {}
|
|
13261
13278
|
};
|
|
13262
13279
|
for (const tool of tools) inheritSubAgentCredentials(tool, credentials);
|
|
13263
13280
|
}
|
|
@@ -15782,10 +15799,11 @@ var init_local_agent_memory = __esm({
|
|
|
15782
15799
|
}
|
|
15783
15800
|
buildTelemetryRecallArgs(telemetry) {
|
|
15784
15801
|
const userId = typeof this.options.memoryContext?.userId === "string" ? this.options.memoryContext.userId : void 0;
|
|
15802
|
+
const tenantId = typeof this.options.memoryContext?.tenantId === "string" ? this.options.memoryContext.tenantId : void 0;
|
|
15785
15803
|
return {
|
|
15786
15804
|
...telemetry !== void 0 ? { telemetry } : {},
|
|
15787
15805
|
...userId !== void 0 ? { userId } : {},
|
|
15788
|
-
namespace: "default",
|
|
15806
|
+
namespace: tenantId ?? "default",
|
|
15789
15807
|
scope: "session"
|
|
15790
15808
|
};
|
|
15791
15809
|
}
|
|
@@ -19119,15 +19137,19 @@ async function collectChildToolResults(run) {
|
|
|
19119
19137
|
${lines.join("\n")}
|
|
19120
19138
|
</subagent-tool-results>`;
|
|
19121
19139
|
}
|
|
19122
|
-
|
|
19123
|
-
const { Agent: Agent2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
|
|
19140
|
+
function buildChildCreateOptions(spec, inherited) {
|
|
19124
19141
|
const model = spec.model ? { id: spec.model } : inherited?.model;
|
|
19125
|
-
|
|
19142
|
+
return {
|
|
19126
19143
|
...inherited?.apiKey !== void 0 ? { apiKey: inherited.apiKey } : {},
|
|
19127
19144
|
...model !== void 0 ? { model } : {},
|
|
19145
|
+
...inherited?.plugins !== void 0 ? { plugins: inherited.plugins } : {},
|
|
19128
19146
|
systemPrompt: spec.instructions,
|
|
19129
19147
|
tools: spec.tools ?? []
|
|
19130
|
-
}
|
|
19148
|
+
};
|
|
19149
|
+
}
|
|
19150
|
+
async function runChildAgent(spec, input, signal, maxSteps, inherited) {
|
|
19151
|
+
const { Agent: Agent2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
|
|
19152
|
+
const agent = await Agent2.create(buildChildCreateOptions(spec, inherited));
|
|
19131
19153
|
try {
|
|
19132
19154
|
const sendOptions = {
|
|
19133
19155
|
...signal !== void 0 ? { signal } : {},
|