@vellumai/assistant 0.9.0 → 0.9.1-staging.1
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/ARCHITECTURE.md +18 -34
- package/bun.lock +7 -8
- package/docs/activation-funnel-telemetry.md +4 -4
- package/docs/architecture/security.md +29 -28
- package/docs/stt-provider-onboarding.md +3 -5
- package/docs/workflows-testing.md +13 -44
- package/docs/workflows.md +3 -5
- package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
- package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
- package/node_modules/@vellumai/gateway-client/src/index.ts +17 -6
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
- package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
- package/openapi.yaml +135 -59
- package/package.json +2 -1
- package/scripts/sync-llm-catalog.ts +6 -15
- package/scripts/sync-web-search-catalog.ts +3 -11
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +14 -26
- package/src/__tests__/agent-loop-compaction-strip.test.ts +240 -0
- package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
- package/src/__tests__/app-dir-path-guard.test.ts +0 -1
- package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
- package/src/__tests__/avatar-identity-sync.test.ts +2 -27
- package/src/__tests__/btw-routes.test.ts +6 -8
- package/src/__tests__/checker.test.ts +0 -3
- package/src/__tests__/config-loader-backfill.test.ts +103 -6
- package/src/__tests__/config-watcher.test.ts +0 -18
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
- package/src/__tests__/credential-broker.test.ts +449 -1
- package/src/__tests__/credential-execution-tools.test.ts +0 -1
- package/src/__tests__/credential-prompt-route.test.ts +3 -4
- package/src/__tests__/credential-routes.test.ts +360 -0
- package/src/__tests__/credential-security-invariants.test.ts +2 -13
- package/src/__tests__/dynamic-page-surface.test.ts +101 -1
- package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
- package/src/__tests__/gateway-only-guard.test.ts +3 -7
- package/src/__tests__/identity-routes.test.ts +0 -189
- package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
- package/src/__tests__/invite-redemption-service.test.ts +4 -4
- package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
- package/src/__tests__/llm-catalog-parity.test.ts +0 -22
- package/src/__tests__/llm-resolver.test.ts +49 -24
- package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
- package/src/__tests__/onboarding-persona-write.test.ts +1 -1
- package/src/__tests__/persona-resolver.test.ts +11 -14
- package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
- package/src/__tests__/registry.test.ts +2 -7
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
- package/src/__tests__/schedule-routes.test.ts +0 -30
- package/src/__tests__/schedule-tools.test.ts +2 -18
- package/src/__tests__/skill-execute-input.test.ts +46 -1
- package/src/__tests__/skill-runtime-path.test.ts +2 -3
- package/src/__tests__/subagent-tools.test.ts +116 -0
- package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
- package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
- package/src/__tests__/token-manager.test.ts +519 -0
- package/src/__tests__/tool-executor.test.ts +0 -79
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
- package/src/__tests__/trusted-contact-verification.test.ts +6 -6
- package/src/__tests__/voice-invite-redemption.test.ts +2 -2
- package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
- package/src/__tests__/workspace-greetings.test.ts +152 -0
- package/src/agent/loop.ts +25 -5
- package/src/api/README.md +6 -6
- package/src/api/responses/conversation-message.ts +2 -4
- package/src/api/responses/home.ts +0 -4
- package/src/approvals/guardian-request-resolvers.ts +2 -2
- package/src/calls/relay-access-wait.ts +1 -1
- package/src/calls/voice-session-bridge.ts +2 -2
- package/src/cli/commands/plugins.ts +143 -2
- package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +313 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +253 -2
- package/src/cli/lib/diff-plugin.ts +346 -0
- package/src/cli/lib/install-from-github.ts +105 -17
- package/src/cli/lib/merge-plugin-tree.ts +228 -0
- package/src/cli/lib/plugin-fingerprint.ts +14 -0
- package/src/cli/lib/upgrade-plugin.ts +270 -10
- package/src/cli/program.ts +0 -2
- package/src/config/bundled-skills/subagent/SKILL.md +4 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
- package/src/config/bundled-skills/workflows/SKILL.md +0 -1
- package/src/config/bundled-tool-registry.ts +2 -7
- package/src/config/call-site-defaults.ts +12 -2
- package/src/config/feature-flag-registry.json +1 -17
- package/src/config/inference-profile-validation.ts +26 -0
- package/src/config/loader.ts +4 -0
- package/src/config/profile-order.ts +28 -0
- package/src/config/schemas/elevenlabs.ts +0 -1
- package/src/config/schemas/platform.ts +0 -8
- package/src/config/seed-inference-profiles.ts +25 -20
- package/src/contacts/contact-store.ts +87 -96
- package/src/contacts/contacts-write.ts +5 -21
- package/src/context/compactor.ts +2 -2
- package/src/credential-execution/process-manager.ts +55 -14
- package/src/credential-execution/prompted-credential.ts +2 -3
- package/src/daemon/config-watcher.ts +0 -4
- package/src/daemon/conversation-agent-loop.ts +15 -4
- package/src/daemon/conversation-slash.ts +2 -23
- package/src/daemon/conversation-tool-setup.ts +11 -3
- package/src/daemon/conversation.ts +2 -0
- package/src/daemon/handlers/config-channels.ts +20 -16
- package/src/daemon/handlers/config-slack-channel.ts +2 -3
- package/src/daemon/lifecycle.ts +0 -7
- package/src/daemon/message-types/conversations.ts +3 -3
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/orphan-reaper.test.ts +0 -19
- package/src/daemon/orphan-reaper.ts +2 -24
- package/src/daemon/server.ts +0 -10
- package/src/home/relationship-state.ts +2 -4
- package/src/memory/__tests__/memory-retrospective-job.test.ts +195 -401
- package/src/memory/bookmark-crud.ts +1 -2
- package/src/memory/db-init.ts +7 -17
- package/src/memory/embedding-backend.ts +23 -0
- package/src/memory/embedding-billing-breaker.ts +96 -0
- package/src/memory/jobs-store.ts +25 -13
- package/src/memory/jobs-worker.ts +52 -0
- package/src/memory/memory-retrospective-constants.ts +4 -4
- package/src/memory/memory-retrospective-job.ts +19 -227
- package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +62 -0
- package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +311 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/migrations/run-migrations.ts +41 -0
- package/src/memory/migrations/validate-migration-state.ts +1 -1
- package/src/memory/schema/contacts.ts +0 -4
- package/src/messaging/providers/slack/adapter.ts +1 -1
- package/src/notifications/adapters/shared.ts +29 -0
- package/src/notifications/adapters/slack.ts +5 -32
- package/src/notifications/adapters/telegram.ts +2 -20
- package/src/notifications/broadcaster.ts +10 -1
- package/src/notifications/home-feed-side-effect.ts +4 -3
- package/src/notifications/notification-utils.ts +17 -19
- package/src/notifications/types.ts +7 -0
- package/src/oauth/AGENTS.md +5 -24
- package/src/plugin-api/constants.ts +1 -1
- package/src/plugin-api/index.ts +6 -1
- package/src/plugin-api/model-profiles.ts +33 -0
- package/src/plugin-api/types.ts +50 -2
- package/src/plugins/defaults/index.ts +25 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +54 -2
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +107 -7
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
- package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
- package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
- package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +1 -1
- package/src/prompts/persona-resolver.ts +2 -2
- package/src/runtime/AGENTS.md +0 -1
- package/src/runtime/actor-trust-resolver.ts +12 -44
- package/src/runtime/btw-sidechain.ts +3 -6
- package/src/runtime/channel-approval-types.ts +18 -45
- package/src/runtime/channel-invite-transports/telegram.ts +4 -4
- package/src/runtime/channel-verification-service.ts +4 -3
- package/src/runtime/invite-redemption-service.ts +3 -3
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +218 -1
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
- package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
- package/src/runtime/routes/btw-routes.ts +1 -27
- package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +2 -2
- package/src/runtime/routes/credential-routes.ts +40 -16
- package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
- package/src/runtime/routes/identity-routes.ts +1 -296
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +171 -5
- package/src/runtime/routes/schedule-routes.ts +0 -22
- package/src/runtime/routes/workflow-routes.test.ts +4 -43
- package/src/runtime/routes/workflow-routes.ts +0 -28
- package/src/runtime/routes/workspace-greetings.ts +55 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -11
- package/src/schedule/inference-profile.ts +2 -14
- package/src/subagent/manager.ts +6 -0
- package/src/subagent/types.ts +6 -0
- package/src/tools/AGENTS.md +3 -3
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/network/web-search-error.ts +1 -1
- package/src/tools/permission-checker.ts +1 -1
- package/src/tools/schedule/create.ts +3 -9
- package/src/tools/schedule/update.ts +2 -10
- package/src/tools/side-effects.ts +2 -17
- package/src/tools/skills/execute.ts +34 -0
- package/src/tools/subagent/spawn.ts +34 -9
- package/src/tools/tool-approval-handler.ts +1 -3
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/ui-surface/definitions.ts +39 -1
- package/src/tools/workflows/run-workflow.test.ts +8 -18
- package/src/util/platform.ts +2 -2
- package/src/workflows/capabilities.ts +2 -3
- package/src/workflows/run-manager.test.ts +0 -25
- package/src/workflows/run-manager.ts +2 -24
- package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
- package/src/__tests__/credential-security-e2e.test.ts +0 -362
- package/src/__tests__/credential-vault-unit.test.ts +0 -1528
- package/src/__tests__/credential-vault.test.ts +0 -1706
- package/src/__tests__/identity-intro-cache.test.ts +0 -315
- package/src/__tests__/secret-onetime-send.test.ts +0 -182
- package/src/cli/commands/__tests__/task.test.ts +0 -914
- package/src/cli/commands/task.ts +0 -771
- package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
- package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
- package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
- package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
- package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
- package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
- package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
- package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
- package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
- package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
- package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
- package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
- package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
- package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
- package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
- package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
- package/src/memory/preloaded-apps.ts +0 -116
- package/src/runtime/routes/identity-intro-cache.ts +0 -172
- package/src/tools/credentials/vault.ts +0 -712
|
@@ -21,11 +21,7 @@ import {
|
|
|
21
21
|
unregisterWorkspaceTool,
|
|
22
22
|
} from "../tools/registry.js";
|
|
23
23
|
import { eagerModuleToolNames, explicitTools } from "../tools/tool-manifest.js";
|
|
24
|
-
import type {
|
|
25
|
-
Tool,
|
|
26
|
-
ToolContext,
|
|
27
|
-
ToolExecutionResult,
|
|
28
|
-
} from "../tools/types.js";
|
|
24
|
+
import type { Tool, ToolContext, ToolExecutionResult } from "../tools/types.js";
|
|
29
25
|
|
|
30
26
|
// Clean up global registry after this file completes to prevent
|
|
31
27
|
// contamination of subsequent test files in combined runs.
|
|
@@ -115,12 +111,11 @@ describe("tool manifest", () => {
|
|
|
115
111
|
expect(eagerModuleToolNames.length).toBe(11);
|
|
116
112
|
});
|
|
117
113
|
|
|
118
|
-
test("explicit tools list includes memory
|
|
114
|
+
test("explicit tools list includes memory tools", () => {
|
|
119
115
|
const names = explicitTools.map((t) => t.name);
|
|
120
116
|
expect(names).toContain("recall");
|
|
121
117
|
expect(names.filter((name) => name === "recall")).toHaveLength(1);
|
|
122
118
|
expect(names).toContain("remember");
|
|
123
|
-
expect(names).toContain("credential_store");
|
|
124
119
|
});
|
|
125
120
|
|
|
126
121
|
test("registered tool count is at least eager + host", async () => {
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
// These tests exercise the PATCH-side `workflowName` validation
|
|
4
|
-
// runs once the `workflows` feature flag is ON (the flag gate short-circuits
|
|
5
|
-
// first when it is off). Mock the flag resolver to ON so the validation path is
|
|
6
|
-
// reachable; the sibling schedule-routes.test.ts keeps the flag OFF and asserts
|
|
7
|
-
// the flag-gate behavior, so the two files do not conflict.
|
|
3
|
+
// These tests exercise the PATCH-side `workflowName` validation.
|
|
8
4
|
mock.module("../util/logger.js", () => ({
|
|
9
5
|
getLogger: () =>
|
|
10
6
|
new Proxy({} as Record<string, unknown>, {
|
|
@@ -12,11 +8,6 @@ mock.module("../util/logger.js", () => ({
|
|
|
12
8
|
}),
|
|
13
9
|
}));
|
|
14
10
|
|
|
15
|
-
mock.module("../config/assistant-feature-flags.js", () => ({
|
|
16
|
-
isAssistantFeatureFlagEnabled: (key: string) => key === "workflows",
|
|
17
|
-
getAssistantFeatureFlagValue: (key: string) => key === "workflows",
|
|
18
|
-
}));
|
|
19
|
-
|
|
20
11
|
mock.module("../config/loader.js", () => ({
|
|
21
12
|
getConfig: () => ({}),
|
|
22
13
|
invalidateConfigCache: () => {},
|
|
@@ -1243,36 +1243,6 @@ describe("POST /schedules — create", () => {
|
|
|
1243
1243
|
).toThrow("Only 'execute' and 'workflow' modes are supported");
|
|
1244
1244
|
});
|
|
1245
1245
|
|
|
1246
|
-
test("rejects workflow-mode creation when the workflows flag is off", () => {
|
|
1247
|
-
// The mocked getConfig returns no feature flags, so `workflows` is off.
|
|
1248
|
-
expect(() =>
|
|
1249
|
-
postCreate({
|
|
1250
|
-
name: "Triage",
|
|
1251
|
-
description: "Triage the inbox every morning",
|
|
1252
|
-
expression: "0 9 * * *",
|
|
1253
|
-
message: "triage inbox",
|
|
1254
|
-
mode: "workflow",
|
|
1255
|
-
workflowName: "triage-inbox",
|
|
1256
|
-
}),
|
|
1257
|
-
).toThrow("Workflows are not enabled");
|
|
1258
|
-
});
|
|
1259
|
-
|
|
1260
|
-
test("rejects PATCH switching to workflow mode when the flag is off", () => {
|
|
1261
|
-
const schedule = createSchedule({
|
|
1262
|
-
name: "Plain execute",
|
|
1263
|
-
cronExpression: "0 9 * * *",
|
|
1264
|
-
message: "hi",
|
|
1265
|
-
syntax: "cron",
|
|
1266
|
-
});
|
|
1267
|
-
const patch = findRoute("schedules/:id", "PATCH");
|
|
1268
|
-
expect(() =>
|
|
1269
|
-
patch.handler({
|
|
1270
|
-
pathParams: { id: schedule.id },
|
|
1271
|
-
body: { mode: "workflow", workflowName: "triage-inbox" },
|
|
1272
|
-
}),
|
|
1273
|
-
).toThrow("Workflows are not enabled");
|
|
1274
|
-
});
|
|
1275
|
-
|
|
1276
1246
|
test("rejects an unparseable expression", () => {
|
|
1277
1247
|
expect(() =>
|
|
1278
1248
|
postCreate({
|
|
@@ -421,7 +421,7 @@ describe("schedule tools — workflow mode", () => {
|
|
|
421
421
|
beforeEach(() => {
|
|
422
422
|
getRawDb().run("DELETE FROM cron_runs");
|
|
423
423
|
getRawDb().run("DELETE FROM cron_jobs");
|
|
424
|
-
setOverridesForTesting({
|
|
424
|
+
setOverridesForTesting({});
|
|
425
425
|
});
|
|
426
426
|
afterAll(() => {
|
|
427
427
|
setOverridesForTesting({});
|
|
@@ -466,22 +466,6 @@ describe("schedule tools — workflow mode", () => {
|
|
|
466
466
|
expect(result.content).toContain("workflow_name is required");
|
|
467
467
|
});
|
|
468
468
|
|
|
469
|
-
test("rejects workflow mode when the workflows flag is off", async () => {
|
|
470
|
-
setOverridesForTesting({}); // flag off
|
|
471
|
-
const result = await executeScheduleCreate(
|
|
472
|
-
{
|
|
473
|
-
name: "Flag off",
|
|
474
|
-
expression: "0 8 * * *",
|
|
475
|
-
mode: "workflow",
|
|
476
|
-
workflow_name: "inbox-triage",
|
|
477
|
-
},
|
|
478
|
-
ctx,
|
|
479
|
-
);
|
|
480
|
-
|
|
481
|
-
expect(result.isError).toBe(true);
|
|
482
|
-
expect(result.content).toContain("workflows are not enabled");
|
|
483
|
-
});
|
|
484
|
-
|
|
485
469
|
test("update to workflow mode requires a workflow_name", async () => {
|
|
486
470
|
await executeScheduleCreate(
|
|
487
471
|
{ name: "To workflow", expression: "0 9 * * *", message: "test" },
|
|
@@ -544,7 +528,7 @@ describe("schedule_create — workflow capability manifest", () => {
|
|
|
544
528
|
beforeEach(() => {
|
|
545
529
|
getRawDb().run("DELETE FROM cron_runs");
|
|
546
530
|
getRawDb().run("DELETE FROM cron_jobs");
|
|
547
|
-
setOverridesForTesting({
|
|
531
|
+
setOverridesForTesting({});
|
|
548
532
|
// Deterministic registry so a declared side-effecting tool resolves.
|
|
549
533
|
__clearRegistryForTesting();
|
|
550
534
|
registerTool(makeFakeTool("file_write"));
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
augmentSkillExecuteError,
|
|
5
|
+
resolveSkillExecuteInput,
|
|
6
|
+
} from "../tools/skills/execute.js";
|
|
4
7
|
|
|
5
8
|
describe("resolveSkillExecuteInput", () => {
|
|
6
9
|
test("returns a correctly nested object unchanged", () => {
|
|
@@ -83,3 +86,45 @@ describe("resolveSkillExecuteInput", () => {
|
|
|
83
86
|
expect(result).toEqual({ foo: "bar" });
|
|
84
87
|
});
|
|
85
88
|
});
|
|
89
|
+
|
|
90
|
+
describe("augmentSkillExecuteError", () => {
|
|
91
|
+
test("appends envelope guidance when an empty-input call errors", () => {
|
|
92
|
+
// The subagent_spawn failure: empty input, tool rejects with a field-level
|
|
93
|
+
// message that says nothing about the skill_execute envelope.
|
|
94
|
+
const result = augmentSkillExecuteError(
|
|
95
|
+
"subagent_spawn",
|
|
96
|
+
{},
|
|
97
|
+
{ content: 'Both "label" and "objective" are required.', isError: true },
|
|
98
|
+
);
|
|
99
|
+
expect(result.isError).toBe(true);
|
|
100
|
+
expect(result.content).toContain(
|
|
101
|
+
'Both "label" and "objective" are required.',
|
|
102
|
+
);
|
|
103
|
+
expect(result.content).toContain("carried no parameters");
|
|
104
|
+
expect(result.content).toContain('"tool": "subagent_spawn"');
|
|
105
|
+
expect(result.content).toContain("inside `input`");
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("leaves errors untouched when parameters were resolved", () => {
|
|
109
|
+
// A non-empty resolved input means the model structured the call; any error
|
|
110
|
+
// is a real tool-level failure, not an envelope-shape mistake.
|
|
111
|
+
const original = {
|
|
112
|
+
content: "Subagent quota exceeded.",
|
|
113
|
+
isError: true,
|
|
114
|
+
};
|
|
115
|
+
const result = augmentSkillExecuteError(
|
|
116
|
+
"subagent_spawn",
|
|
117
|
+
{ label: "x", objective: "y" },
|
|
118
|
+
original,
|
|
119
|
+
);
|
|
120
|
+
expect(result).toBe(original);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("leaves successful empty-input calls untouched", () => {
|
|
124
|
+
// Tools that legitimately accept no parameters (e.g. subagent_status) must
|
|
125
|
+
// not have guidance appended to their successful results.
|
|
126
|
+
const original = { content: "No subagents running.", isError: false };
|
|
127
|
+
const result = augmentSkillExecuteError("subagent_status", {}, original);
|
|
128
|
+
expect(result).toBe(original);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -9,9 +9,8 @@
|
|
|
9
9
|
* branches (macOS `.app` Resources, next-to-binary) key off
|
|
10
10
|
* `import.meta.dir.startsWith("/$bunfs/")`, so at test time only the
|
|
11
11
|
* source-mode early-return is exercised here; the compiled branch is
|
|
12
|
-
* covered structurally via the signing + packaging step in
|
|
13
|
-
* `clients/macos/
|
|
14
|
-
* supervisor integration test added in PR 27.
|
|
12
|
+
* covered structurally via the Electron signing + packaging step in
|
|
13
|
+
* `clients/macos/scripts/pack.sh`.
|
|
15
14
|
*/
|
|
16
15
|
|
|
17
16
|
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
@@ -6,6 +6,27 @@ import { describe, expect, mock, test } from "bun:test";
|
|
|
6
6
|
let mockGetMessages: (
|
|
7
7
|
conversationId: string,
|
|
8
8
|
) => Array<{ role: string; content: string }> | null = () => null;
|
|
9
|
+
const mockProfiles = {
|
|
10
|
+
balanced: {},
|
|
11
|
+
disabled: { status: "disabled" },
|
|
12
|
+
"quality-optimized": {},
|
|
13
|
+
};
|
|
14
|
+
mock.module("../config/loader.js", () => ({
|
|
15
|
+
getConfigReadOnly: () => ({
|
|
16
|
+
llm: { profiles: mockProfiles },
|
|
17
|
+
}),
|
|
18
|
+
getConfig: () => ({
|
|
19
|
+
llm: {
|
|
20
|
+
default: {
|
|
21
|
+
provider: "anthropic",
|
|
22
|
+
provider_connection: "anthropic-managed",
|
|
23
|
+
model: "claude-opus-4-7",
|
|
24
|
+
},
|
|
25
|
+
profiles: mockProfiles,
|
|
26
|
+
},
|
|
27
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
28
|
+
}),
|
|
29
|
+
}));
|
|
9
30
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
10
31
|
setConversationOriginChannelIfUnset: () => {},
|
|
11
32
|
updateConversationContextWindow: () => {},
|
|
@@ -140,6 +161,7 @@ describe("Subagent tool definitions", () => {
|
|
|
140
161
|
const def = findTool("subagent_spawn");
|
|
141
162
|
expect(def).toBeDefined();
|
|
142
163
|
expect(def.input_schema.required).toEqual(["label", "objective"]);
|
|
164
|
+
expect(def.input_schema.properties.inference_profile).toBeDefined();
|
|
143
165
|
});
|
|
144
166
|
|
|
145
167
|
test("abort tool has correct definition", () => {
|
|
@@ -422,6 +444,100 @@ describe("Subagent spawn success and failure", () => {
|
|
|
422
444
|
}
|
|
423
445
|
});
|
|
424
446
|
|
|
447
|
+
test("spawn passes explicit inference_profile to manager over inherited override", async () => {
|
|
448
|
+
const manager = getSubagentManager();
|
|
449
|
+
const originalSpawn = manager.spawn.bind(manager);
|
|
450
|
+
let capturedConfig: Record<string, unknown> | undefined;
|
|
451
|
+
|
|
452
|
+
manager.spawn = async (config: Record<string, unknown>) => {
|
|
453
|
+
capturedConfig = config;
|
|
454
|
+
return "profile-subagent-id";
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
const result = await executeSubagentSpawn(
|
|
459
|
+
{
|
|
460
|
+
label: "Profile test",
|
|
461
|
+
objective: "Do it with a chosen model profile",
|
|
462
|
+
inference_profile: "quality-optimized",
|
|
463
|
+
},
|
|
464
|
+
makeContext("sess-spawn-profile", {
|
|
465
|
+
sendToClient: () => {},
|
|
466
|
+
overrideProfile: "balanced",
|
|
467
|
+
}),
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
expect(result.isError).toBe(false);
|
|
471
|
+
expect(capturedConfig).toBeDefined();
|
|
472
|
+
expect(capturedConfig!.overrideProfile).toBe("quality-optimized");
|
|
473
|
+
expect(capturedConfig!.forceOverrideProfile).toBe(true);
|
|
474
|
+
} finally {
|
|
475
|
+
manager.spawn = originalSpawn;
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
test("spawn returns error for unknown inference_profile", async () => {
|
|
480
|
+
const manager = getSubagentManager();
|
|
481
|
+
const originalSpawn = manager.spawn.bind(manager);
|
|
482
|
+
let spawnCalled = false;
|
|
483
|
+
|
|
484
|
+
manager.spawn = async () => {
|
|
485
|
+
spawnCalled = true;
|
|
486
|
+
return "profile-subagent-id";
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
try {
|
|
490
|
+
const result = await executeSubagentSpawn(
|
|
491
|
+
{
|
|
492
|
+
label: "Bad profile",
|
|
493
|
+
objective: "Do it",
|
|
494
|
+
inference_profile: "does-not-exist",
|
|
495
|
+
},
|
|
496
|
+
makeContext("sess-spawn-bad-profile", { sendToClient: () => {} }),
|
|
497
|
+
);
|
|
498
|
+
|
|
499
|
+
expect(result.isError).toBe(true);
|
|
500
|
+
expect(result.content).toContain(
|
|
501
|
+
'Inference profile "does-not-exist" is not defined',
|
|
502
|
+
);
|
|
503
|
+
expect(spawnCalled).toBe(false);
|
|
504
|
+
} finally {
|
|
505
|
+
manager.spawn = originalSpawn;
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
test("spawn returns error for disabled inference_profile", async () => {
|
|
510
|
+
const manager = getSubagentManager();
|
|
511
|
+
const originalSpawn = manager.spawn.bind(manager);
|
|
512
|
+
let spawnCalled = false;
|
|
513
|
+
|
|
514
|
+
manager.spawn = async () => {
|
|
515
|
+
spawnCalled = true;
|
|
516
|
+
return "profile-subagent-id";
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
try {
|
|
520
|
+
const result = await executeSubagentSpawn(
|
|
521
|
+
{
|
|
522
|
+
label: "Disabled profile",
|
|
523
|
+
objective: "Do it",
|
|
524
|
+
inference_profile: "disabled",
|
|
525
|
+
},
|
|
526
|
+
makeContext("sess-spawn-disabled-profile", {
|
|
527
|
+
sendToClient: () => {},
|
|
528
|
+
}),
|
|
529
|
+
);
|
|
530
|
+
|
|
531
|
+
expect(result.isError).toBe(true);
|
|
532
|
+
expect(result.content).toContain(
|
|
533
|
+
'Inference profile "disabled" is disabled',
|
|
534
|
+
);
|
|
535
|
+
expect(spawnCalled).toBe(false);
|
|
536
|
+
} finally {
|
|
537
|
+
manager.spawn = originalSpawn;
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
|
|
425
541
|
test("spawn handles non-Error throws gracefully", async () => {
|
|
426
542
|
const manager = getSubagentManager();
|
|
427
543
|
const originalSpawn = manager.spawn.bind(manager);
|