@vellumai/assistant 0.8.2 → 0.8.3
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 +11 -12
- package/docker-entrypoint.sh +13 -1
- package/docker-init-apt-root.sh +79 -6
- package/openapi.yaml +336 -21
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +272 -0
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- package/src/__tests__/context-token-estimator.test.ts +30 -65
- package/src/__tests__/conversation-agent-loop.test.ts +57 -1
- package/src/__tests__/conversation-media-retry.test.ts +19 -8
- package/src/__tests__/conversation-runtime-assembly.test.ts +26 -4
- package/src/__tests__/date-context.test.ts +45 -0
- package/src/__tests__/external-plugin-loader.test.ts +91 -19
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/host-app-control-proxy.test.ts +241 -0
- package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
- package/src/__tests__/injector-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +5 -0
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -2
- package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +3 -0
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
- package/src/__tests__/llm-resolver.test.ts +255 -2
- package/src/__tests__/managed-profile-guard.test.ts +10 -0
- package/src/__tests__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
- package/src/__tests__/openai-provider.test.ts +218 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- package/src/__tests__/platform-proxy-context.test.ts +6 -1
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
- package/src/__tests__/plugin-types.test.ts +2 -2
- package/src/__tests__/provider-catalog-visibility.test.ts +16 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/system-prompt.test.ts +6 -73
- package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
- package/src/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/agent/loop.ts +167 -18
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +14 -0
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +469 -0
- package/src/cli/commands/notifications.ts +65 -35
- package/src/cli/commands/plugins.ts +67 -0
- package/src/cli/commands/schedules.ts +297 -5
- package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
- package/src/cli/lib/install-from-github.ts +8 -9
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/program.ts +14 -0
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/call-site-defaults.ts +105 -0
- package/src/config/feature-flag-registry.json +21 -29
- package/src/config/llm-resolver.ts +52 -1
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +3 -3
- package/src/config/schemas/channels.ts +9 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +14 -0
- package/src/config/schemas/llm.ts +1 -3
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +4 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/context/compactor.ts +72 -12
- package/src/context/token-estimator.ts +32 -34
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
- package/src/daemon/conversation-agent-loop-handlers.ts +78 -0
- package/src/daemon/conversation-agent-loop.ts +29 -2
- package/src/daemon/conversation-runtime-assembly.ts +9 -0
- package/src/daemon/conversation.ts +0 -7
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +289 -0
- package/src/daemon/handlers/conversations.ts +1 -0
- package/src/daemon/host-app-control-proxy.ts +69 -18
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/lifecycle.ts +49 -61
- package/src/daemon/memory-v2-startup.ts +49 -13
- package/src/daemon/message-types/notifications.ts +21 -0
- package/src/daemon/pkb-reminder-builder.test.ts +10 -53
- package/src/daemon/pkb-reminder-builder.ts +4 -19
- package/src/daemon/process-message.ts +3 -0
- package/src/daemon/skill-memory-refresh.ts +5 -1
- package/src/daemon/wake-target-adapter.ts +2 -0
- package/src/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -0
- package/src/heartbeat/heartbeat-service.ts +34 -191
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/feed-types.ts +14 -2
- package/src/ipc/cli-client.ts +147 -45
- package/src/memory/__tests__/conversation-queries.test.ts +220 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +87 -4
- package/src/memory/conversation-queries.ts +87 -1
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +6 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
- package/src/memory/graph/conversation-graph-memory.ts +18 -6
- package/src/memory/graph/tools.ts +6 -37
- package/src/memory/invite-store.ts +53 -0
- package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/memory-retrospective-enqueue.ts +1 -20
- package/src/memory/memory-retrospective-job.ts +33 -6
- package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +2 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection.test.ts +190 -3
- package/src/memory/v2/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection.ts +49 -20
- package/src/memory/v2/page-index.ts +38 -13
- package/src/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +11 -2
- package/src/notifications/__tests__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +430 -7
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +111 -44
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +1 -0
- package/src/notifications/home-feed-side-effect.ts +85 -6
- package/src/notifications/signal.ts +0 -4
- package/src/notifications/types.ts +8 -0
- package/src/oauth/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +13 -4
- package/src/plugins/defaults/injectors.ts +38 -19
- package/src/plugins/external-plugin-loader.ts +82 -10
- package/src/plugins/types.ts +16 -7
- package/src/prompts/__tests__/system-prompt.test.ts +6 -51
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
- package/src/prompts/system-prompt.ts +0 -8
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/system-sections.ts +0 -9
- package/src/providers/__tests__/inference.test.ts +2 -0
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +63 -13
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +9 -20
- package/src/providers/inference/auth.ts +12 -0
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/connections.ts +85 -5
- package/src/providers/inference/resolve-auth.ts +2 -0
- package/src/providers/model-catalog.ts +199 -244
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +159 -6
- package/src/providers/openrouter/client.ts +42 -4
- package/src/providers/platform-proxy/constants.ts +3 -4
- package/src/providers/provider-catalog-visibility.ts +3 -1
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +30 -1
- package/src/runtime/agent-wake.ts +61 -1
- package/src/runtime/auth/route-policy.ts +13 -0
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +0 -47
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +66 -4
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- package/src/runtime/routes/channel-availability-routes.ts +5 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -0
- package/src/runtime/routes/conversation-query-routes.ts +70 -11
- package/src/runtime/routes/conversation-routes.ts +7 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +134 -1
- package/src/runtime/routes/integrations/a2a.ts +235 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
- package/src/runtime/routes/subagents-routes.ts +41 -0
- package/src/subagent/manager.ts +2 -0
- package/src/tools/memory/register.ts +1 -9
- package/src/tools/registry.ts +2 -2
- package/src/tools/types.ts +37 -2
- package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route handlers for A2A integration config endpoints.
|
|
3
|
+
*
|
|
4
|
+
* GET /v1/integrations/a2a/config — get current A2A config status
|
|
5
|
+
* POST /v1/integrations/a2a/config — enable A2A channel
|
|
6
|
+
* DELETE /v1/integrations/a2a/config — disable A2A channel
|
|
7
|
+
* POST /v1/integrations/a2a/invite — create a shareable A2A invite token
|
|
8
|
+
* POST /v1/integrations/a2a/invite/complete — sender-side invite completion
|
|
9
|
+
* POST /v1/integrations/a2a/invite/redeem — receiver-side invite redemption
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { isA2AEnabled } from "../../../a2a/feature-gate.js";
|
|
13
|
+
import { getConfig } from "../../../config/loader.js";
|
|
14
|
+
import {
|
|
15
|
+
clearA2AConfig,
|
|
16
|
+
completeA2AInvite,
|
|
17
|
+
createA2AInvite,
|
|
18
|
+
getA2AConfig,
|
|
19
|
+
redeemA2AInvite,
|
|
20
|
+
setA2AConfig,
|
|
21
|
+
} from "../../../daemon/handlers/config-a2a.js";
|
|
22
|
+
import { BadRequestError } from "../errors.js";
|
|
23
|
+
import type { RouteDefinition, RouteHandlerArgs } from "../types.js";
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Helpers
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
function assertA2AFlag(): void {
|
|
30
|
+
if (!isA2AEnabled(getConfig())) {
|
|
31
|
+
throw new BadRequestError("A2A channel is not available");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Handlers
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
function handleGetA2AConfig() {
|
|
40
|
+
assertA2AFlag();
|
|
41
|
+
return getA2AConfig();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function handleSetA2AConfig() {
|
|
45
|
+
assertA2AFlag();
|
|
46
|
+
const result = setA2AConfig();
|
|
47
|
+
if (!result.success) {
|
|
48
|
+
throw new BadRequestError(result.error ?? "Failed to enable A2A");
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function handleClearA2AConfig() {
|
|
54
|
+
assertA2AFlag();
|
|
55
|
+
return clearA2AConfig();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function handleCreateA2AInvite({ body = {} }: RouteHandlerArgs) {
|
|
59
|
+
assertA2AFlag();
|
|
60
|
+
const { expiresInHours } = body as { expiresInHours?: unknown };
|
|
61
|
+
if (expiresInHours !== undefined) {
|
|
62
|
+
if (
|
|
63
|
+
typeof expiresInHours !== "number" ||
|
|
64
|
+
!Number.isFinite(expiresInHours) ||
|
|
65
|
+
expiresInHours <= 0
|
|
66
|
+
) {
|
|
67
|
+
throw new BadRequestError(
|
|
68
|
+
"expiresInHours must be a positive finite number",
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const result = createA2AInvite({
|
|
73
|
+
expiresInHours: expiresInHours as number | undefined,
|
|
74
|
+
});
|
|
75
|
+
if (!result.success) {
|
|
76
|
+
throw new BadRequestError(result.error ?? "Failed to create A2A invite");
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function handleCompleteA2AInvite({ body = {} }: RouteHandlerArgs) {
|
|
82
|
+
const { token, senderAssistantId, acceptor } = body as {
|
|
83
|
+
token?: unknown;
|
|
84
|
+
senderAssistantId?: unknown;
|
|
85
|
+
acceptor?: {
|
|
86
|
+
assistantId?: unknown;
|
|
87
|
+
displayName?: unknown;
|
|
88
|
+
gatewayUrl?: unknown;
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
if (typeof token !== "string" || !token) {
|
|
93
|
+
throw new BadRequestError(
|
|
94
|
+
"token is required and must be a non-empty string",
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
if (typeof senderAssistantId !== "string" || !senderAssistantId) {
|
|
98
|
+
throw new BadRequestError(
|
|
99
|
+
"senderAssistantId is required and must be a non-empty string",
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
if (
|
|
103
|
+
!acceptor ||
|
|
104
|
+
typeof acceptor.assistantId !== "string" ||
|
|
105
|
+
!acceptor.assistantId ||
|
|
106
|
+
typeof acceptor.displayName !== "string" ||
|
|
107
|
+
!acceptor.displayName ||
|
|
108
|
+
typeof acceptor.gatewayUrl !== "string" ||
|
|
109
|
+
!acceptor.gatewayUrl
|
|
110
|
+
) {
|
|
111
|
+
throw new BadRequestError(
|
|
112
|
+
"acceptor must include non-empty assistantId, displayName, and gatewayUrl",
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const result = completeA2AInvite({
|
|
117
|
+
token,
|
|
118
|
+
senderAssistantId,
|
|
119
|
+
acceptor: {
|
|
120
|
+
assistantId: acceptor.assistantId,
|
|
121
|
+
displayName: acceptor.displayName,
|
|
122
|
+
gatewayUrl: acceptor.gatewayUrl,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
if (!result.success) {
|
|
126
|
+
throw new BadRequestError(result.error ?? "Failed to complete A2A invite");
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function handleRedeemA2AInvite({ body = {} }: RouteHandlerArgs) {
|
|
132
|
+
const { sender } = body as {
|
|
133
|
+
sender?: {
|
|
134
|
+
assistantId?: unknown;
|
|
135
|
+
displayName?: unknown;
|
|
136
|
+
gatewayUrl?: unknown;
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
if (
|
|
141
|
+
!sender ||
|
|
142
|
+
typeof sender.assistantId !== "string" ||
|
|
143
|
+
!sender.assistantId ||
|
|
144
|
+
typeof sender.displayName !== "string" ||
|
|
145
|
+
!sender.displayName ||
|
|
146
|
+
typeof sender.gatewayUrl !== "string" ||
|
|
147
|
+
!sender.gatewayUrl
|
|
148
|
+
) {
|
|
149
|
+
throw new BadRequestError(
|
|
150
|
+
"sender must include non-empty assistantId, displayName, and gatewayUrl",
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const result = redeemA2AInvite({
|
|
155
|
+
sender: {
|
|
156
|
+
assistantId: sender.assistantId,
|
|
157
|
+
displayName: sender.displayName,
|
|
158
|
+
gatewayUrl: sender.gatewayUrl,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
if (!result.success) {
|
|
162
|
+
throw new BadRequestError(result.error ?? "Failed to redeem A2A invite");
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
// Route definitions
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
|
|
171
|
+
export const ROUTES: RouteDefinition[] = [
|
|
172
|
+
{
|
|
173
|
+
operationId: "integrations_a2a_config_get",
|
|
174
|
+
endpoint: "integrations/a2a/config",
|
|
175
|
+
method: "GET",
|
|
176
|
+
summary: "Get A2A config",
|
|
177
|
+
description: "Check current A2A channel configuration status.",
|
|
178
|
+
tags: ["integrations"],
|
|
179
|
+
requirePolicyEnforcement: true,
|
|
180
|
+
handler: () => handleGetA2AConfig(),
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
operationId: "integrations_a2a_config_post",
|
|
184
|
+
endpoint: "integrations/a2a/config",
|
|
185
|
+
method: "POST",
|
|
186
|
+
summary: "Enable A2A channel",
|
|
187
|
+
description: "Enable the A2A channel for inter-assistant communication.",
|
|
188
|
+
tags: ["integrations"],
|
|
189
|
+
requirePolicyEnforcement: true,
|
|
190
|
+
handler: () => handleSetA2AConfig(),
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
operationId: "integrations_a2a_config_delete",
|
|
194
|
+
endpoint: "integrations/a2a/config",
|
|
195
|
+
method: "DELETE",
|
|
196
|
+
summary: "Disable A2A channel",
|
|
197
|
+
description: "Disable the A2A channel.",
|
|
198
|
+
tags: ["integrations"],
|
|
199
|
+
requirePolicyEnforcement: true,
|
|
200
|
+
handler: () => handleClearA2AConfig(),
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
operationId: "integrations_a2a_invite_post",
|
|
204
|
+
endpoint: "integrations/a2a/invite",
|
|
205
|
+
method: "POST",
|
|
206
|
+
summary: "Create A2A invite",
|
|
207
|
+
description:
|
|
208
|
+
"Create a shareable A2A invite token for link-based contact creation.",
|
|
209
|
+
tags: ["integrations"],
|
|
210
|
+
requirePolicyEnforcement: true,
|
|
211
|
+
handler: handleCreateA2AInvite,
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
operationId: "integrations_a2a_invite_complete_post",
|
|
215
|
+
endpoint: "integrations/a2a/invite/complete",
|
|
216
|
+
method: "POST",
|
|
217
|
+
summary: "Complete A2A invite (sender side)",
|
|
218
|
+
description:
|
|
219
|
+
"Called by the platform to finalize the sender side of a link-based A2A connection.",
|
|
220
|
+
tags: ["integrations"],
|
|
221
|
+
requirePolicyEnforcement: true,
|
|
222
|
+
handler: handleCompleteA2AInvite,
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
operationId: "integrations_a2a_invite_redeem_post",
|
|
226
|
+
endpoint: "integrations/a2a/invite/redeem",
|
|
227
|
+
method: "POST",
|
|
228
|
+
summary: "Redeem A2A invite (receiver side)",
|
|
229
|
+
description:
|
|
230
|
+
"Called by the platform to create a trusted contact on the receiver side of a link-based A2A connection.",
|
|
231
|
+
tags: ["integrations"],
|
|
232
|
+
requirePolicyEnforcement: true,
|
|
233
|
+
handler: handleRedeemA2AInvite,
|
|
234
|
+
},
|
|
235
|
+
];
|
|
@@ -1,10 +1,20 @@
|
|
|
1
|
+
import { resolveDefaultProfileKey } from "../../config/llm-resolver.js";
|
|
2
|
+
import { loadConfig } from "../../config/loader.js";
|
|
1
3
|
import { CALL_SITE_CATALOG, CALL_SITE_DOMAINS } from "../../config/schemas/call-site-catalog.js";
|
|
4
|
+
import type { LLMCallSite } from "../../config/schemas/llm.js";
|
|
2
5
|
import type { RouteDefinition } from "./types.js";
|
|
3
6
|
|
|
4
7
|
async function handleGetCallSites() {
|
|
8
|
+
const { llm } = loadConfig();
|
|
5
9
|
return {
|
|
6
10
|
domains: CALL_SITE_DOMAINS,
|
|
7
|
-
callSites: CALL_SITE_CATALOG
|
|
11
|
+
callSites: CALL_SITE_CATALOG.map((entry) => ({
|
|
12
|
+
...entry,
|
|
13
|
+
defaultProfile: resolveDefaultProfileKey(
|
|
14
|
+
entry.id as LLMCallSite,
|
|
15
|
+
llm,
|
|
16
|
+
),
|
|
17
|
+
})),
|
|
8
18
|
};
|
|
9
19
|
}
|
|
10
20
|
|
|
@@ -188,6 +188,47 @@ function getSubagentDetail(
|
|
|
188
188
|
// ---------------------------------------------------------------------------
|
|
189
189
|
|
|
190
190
|
export const ROUTES: RouteDefinition[] = [
|
|
191
|
+
{
|
|
192
|
+
operationId: "reconcileSubagents",
|
|
193
|
+
endpoint: "subagents/reconcile",
|
|
194
|
+
method: "GET",
|
|
195
|
+
policyKey: "subagents",
|
|
196
|
+
summary: "Reconcile subagent live status",
|
|
197
|
+
description:
|
|
198
|
+
"Returns the live in-memory status of all subagents known to the daemon for a given parent conversation. Subagents not in the response are orphaned.",
|
|
199
|
+
tags: ["subagents"],
|
|
200
|
+
queryParams: [
|
|
201
|
+
{
|
|
202
|
+
name: "parentConversationId",
|
|
203
|
+
schema: { type: "string" },
|
|
204
|
+
description: "Parent conversation ID",
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
responseBody: z.object({
|
|
208
|
+
subagents: z.record(
|
|
209
|
+
z.string(),
|
|
210
|
+
z.object({
|
|
211
|
+
status: z.string(),
|
|
212
|
+
}),
|
|
213
|
+
),
|
|
214
|
+
}),
|
|
215
|
+
handler: ({ queryParams }) => {
|
|
216
|
+
const parentConversationId = queryParams?.parentConversationId;
|
|
217
|
+
if (!parentConversationId) {
|
|
218
|
+
throw new BadRequestError(
|
|
219
|
+
"parentConversationId query parameter is required",
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
const manager = getSubagentManager();
|
|
223
|
+
const children = manager.getChildrenOf(parentConversationId);
|
|
224
|
+
const subagents: Record<string, { status: string }> = {};
|
|
225
|
+
for (const child of children) {
|
|
226
|
+
subagents[child.config.id] = { status: child.status };
|
|
227
|
+
}
|
|
228
|
+
return { subagents };
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
|
|
191
232
|
{
|
|
192
233
|
operationId: "getSubagentDetail",
|
|
193
234
|
endpoint: "subagents/:id",
|
package/src/subagent/manager.ts
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
type RememberInput,
|
|
7
7
|
} from "../../memory/graph/tool-handlers.js";
|
|
8
8
|
import {
|
|
9
|
-
getRememberDescription,
|
|
10
9
|
graphRecallDefinition,
|
|
11
10
|
graphRememberDefinition,
|
|
12
11
|
} from "../../memory/graph/tools.js";
|
|
@@ -19,19 +18,12 @@ import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
|
19
18
|
|
|
20
19
|
class RememberTool implements Tool {
|
|
21
20
|
name = "remember";
|
|
22
|
-
// Surfaced in registry listings. The flag-aware description used during
|
|
23
|
-
// actual tool dispatch is computed lazily in `getDefinition()` below so it
|
|
24
|
-
// tracks config changes across daemon lifetime without needing a tool
|
|
25
|
-
// re-registration pass.
|
|
26
21
|
description = graphRememberDefinition.description;
|
|
27
22
|
category = "memory";
|
|
28
23
|
defaultRiskLevel = RiskLevel.Low;
|
|
29
24
|
|
|
30
25
|
getDefinition(): ToolDefinition {
|
|
31
|
-
return
|
|
32
|
-
...graphRememberDefinition,
|
|
33
|
-
description: getRememberDescription(getConfig()),
|
|
34
|
-
};
|
|
26
|
+
return graphRememberDefinition;
|
|
35
27
|
}
|
|
36
28
|
|
|
37
29
|
async execute(
|
package/src/tools/registry.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { hostFileWriteTool } from "./host-filesystem/write.js";
|
|
|
10
10
|
import { hostShellTool } from "./host-terminal/host-shell.js";
|
|
11
11
|
import { toProviderSafeToolName } from "./provider-tool-name.js";
|
|
12
12
|
import { registerSystemTools } from "./system/register.js";
|
|
13
|
-
import type {
|
|
13
|
+
import type { LoadedPluginTool, Tool } from "./types.js";
|
|
14
14
|
import { allUiSurfaceTools } from "./ui-surface/definitions.js";
|
|
15
15
|
import { registerUiSurfaceTools } from "./ui-surface/registry.js";
|
|
16
16
|
|
|
@@ -193,7 +193,7 @@ export function registerSkillTools(newTools: Tool[]): Tool[] {
|
|
|
193
193
|
*/
|
|
194
194
|
export function registerPluginTools(
|
|
195
195
|
pluginName: string,
|
|
196
|
-
newTools:
|
|
196
|
+
newTools: LoadedPluginTool[],
|
|
197
197
|
): Tool[] {
|
|
198
198
|
const stamped: Tool[] = newTools.map((pluginTool) => {
|
|
199
199
|
const { input_schema, ...rest } = pluginTool;
|
package/src/tools/types.ts
CHANGED
|
@@ -376,16 +376,51 @@ export interface Tool {
|
|
|
376
376
|
|
|
377
377
|
/**
|
|
378
378
|
* Plugin-facing tool shape. The narrow surface plugin authors implement;
|
|
379
|
-
* differs from {@link Tool} in
|
|
379
|
+
* differs from {@link Tool} in four ways:
|
|
380
380
|
* - Plugins declare `input_schema` as a top-level field instead of
|
|
381
381
|
* implementing `getDefinition()`. The registration boundary synthesizes
|
|
382
382
|
* `getDefinition()` from `{name, description, input_schema}` before the
|
|
383
383
|
* tool enters the internal registry.
|
|
384
|
+
* - `name` is derived from the tool file's basename by the external plugin
|
|
385
|
+
* loader.
|
|
384
386
|
* - `category` is registry-owned and stamped to `"plugin"` when the tool is
|
|
385
387
|
* registered.
|
|
386
388
|
* - All ownership stamps (`origin`, `ownerPluginId`, etc.) are set
|
|
387
389
|
* authoritatively by the bootstrap; plugin authors leave them blank.
|
|
390
|
+
*
|
|
391
|
+
* Every author-visible field is optional. The loader fills the four
|
|
392
|
+
* normally-required slots (`description`, `defaultRiskLevel`,
|
|
393
|
+
* `input_schema`, `execute`) with documented defaults when a plugin omits
|
|
394
|
+
* them — see `applyPluginToolDefaults` in `external-plugin-loader.ts`.
|
|
395
|
+
* A nameless, body-less `export default {}` is a valid (if useless) tool;
|
|
396
|
+
* misconfigured tools surface at call time rather than blocking plugin
|
|
397
|
+
* load.
|
|
398
|
+
*/
|
|
399
|
+
export type PluginTool = Omit<
|
|
400
|
+
Tool,
|
|
401
|
+
"category" | "getDefinition" | "name" | "description" | "defaultRiskLevel"
|
|
402
|
+
> & {
|
|
403
|
+
description?: string;
|
|
404
|
+
defaultRiskLevel?: RiskLevel;
|
|
405
|
+
input_schema?: object;
|
|
406
|
+
execute?: (
|
|
407
|
+
input: Record<string, unknown>,
|
|
408
|
+
context: ToolContext,
|
|
409
|
+
) => Promise<ToolExecutionResult>;
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Plugin tool after the external loader has derived its registry name and
|
|
414
|
+
* filled defaults for any author-omitted fields. All four normally-required
|
|
415
|
+
* slots are guaranteed present.
|
|
388
416
|
*/
|
|
389
|
-
export type
|
|
417
|
+
export type LoadedPluginTool = PluginTool & {
|
|
418
|
+
name: string;
|
|
419
|
+
description: string;
|
|
420
|
+
defaultRiskLevel: RiskLevel;
|
|
390
421
|
input_schema: object;
|
|
422
|
+
execute: (
|
|
423
|
+
input: Record<string, unknown>,
|
|
424
|
+
context: ToolContext,
|
|
425
|
+
) => Promise<ToolExecutionResult>;
|
|
391
426
|
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
// Upgrade callSites.memoryRouter from the 077-seeded
|
|
7
|
+
// {model: "claude-sonnet-4-6", contextWindow: {maxInputTokens: 1_000_000}}
|
|
8
|
+
// shape to {profile: "balanced"} so the router rides the workspace's active
|
|
9
|
+
// inference profile (with thinking enabled, higher effort, etc.) instead of a
|
|
10
|
+
// bare model pin.
|
|
11
|
+
//
|
|
12
|
+
// Two skip conditions guard against runtime regressions:
|
|
13
|
+
//
|
|
14
|
+
// 1. BYOK / non-Anthropic workspaces. `balanced` resolves to the managed
|
|
15
|
+
// Anthropic connection (see seedInferenceProfiles), which off-platform
|
|
16
|
+
// installs explicitly disable. Forcing `balanced` there would make
|
|
17
|
+
// getConfiguredProvider("memoryRouter") return null and silently
|
|
18
|
+
// disable memory injection. Detect this by inspecting llm.default.provider
|
|
19
|
+
// — same heuristic migration 077 used to gate its seed.
|
|
20
|
+
//
|
|
21
|
+
// 2. User-customized memoryRouter config. If the existing entry isn't the
|
|
22
|
+
// exact 077-seeded shape (and isn't already {profile: "balanced"}), the
|
|
23
|
+
// user — or a platform overlay — chose those values deliberately. Match
|
|
24
|
+
// 077's pattern of preserving any prior config.
|
|
25
|
+
export const memoryRouterBalancedProfileMigration: WorkspaceMigration = {
|
|
26
|
+
id: "087-memory-router-balanced-profile",
|
|
27
|
+
description:
|
|
28
|
+
"Set callSites.memoryRouter to { profile: 'balanced' }, dropping the seeded model and contextWindow override",
|
|
29
|
+
run(workspaceDir: string): void {
|
|
30
|
+
if (process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH) return;
|
|
31
|
+
|
|
32
|
+
const configPath = join(workspaceDir, "config.json");
|
|
33
|
+
const configExisted = existsSync(configPath);
|
|
34
|
+
|
|
35
|
+
let config: Record<string, unknown> = {};
|
|
36
|
+
if (configExisted) {
|
|
37
|
+
try {
|
|
38
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
39
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
40
|
+
config = raw as Record<string, unknown>;
|
|
41
|
+
} catch {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const llm = readObject(config.llm) ?? {};
|
|
47
|
+
|
|
48
|
+
const explicitProvider = readString(readObject(llm.default)?.provider);
|
|
49
|
+
if (explicitProvider !== undefined && explicitProvider !== "anthropic") {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const callSites = readObject(llm.callSites) ?? {};
|
|
54
|
+
const existing = readObject(callSites.memoryRouter);
|
|
55
|
+
|
|
56
|
+
if (existing !== null && !isSeededBy077(existing)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
callSites.memoryRouter = { profile: "balanced" };
|
|
61
|
+
llm.callSites = callSites;
|
|
62
|
+
config.llm = llm;
|
|
63
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
64
|
+
},
|
|
65
|
+
down(_workspaceDir: string): void {
|
|
66
|
+
// Forward-only.
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// True when the entry looks exactly like what migration 077 wrote: a model pin
|
|
71
|
+
// of claude-sonnet-4-6 plus the 1M-token context window, and nothing else.
|
|
72
|
+
function isSeededBy077(entry: Record<string, unknown>): boolean {
|
|
73
|
+
const keys = Object.keys(entry);
|
|
74
|
+
if (keys.length !== 2) return false;
|
|
75
|
+
if (entry.model !== "claude-sonnet-4-6") return false;
|
|
76
|
+
const contextWindow = readObject(entry.contextWindow);
|
|
77
|
+
if (contextWindow === null) return false;
|
|
78
|
+
const cwKeys = Object.keys(contextWindow);
|
|
79
|
+
return cwKeys.length === 1 && contextWindow.maxInputTokens === 1_000_000;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function readObject(value: unknown): Record<string, unknown> | null {
|
|
83
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
return value as Record<string, unknown>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function readString(value: unknown): string | undefined {
|
|
90
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
91
|
+
}
|
|
@@ -84,6 +84,7 @@ import { systemPromptPrefixToFileMigration } from "./083-system-prompt-prefix-to
|
|
|
84
84
|
import { removeLegacySkillsIndexMigration } from "./084-remove-legacy-skills-index.js";
|
|
85
85
|
import { memoryV2Bm25BReembedDisabledV2PagesMigration } from "./085-memory-v2-bm25-b-reembed-disabled-v2-pages.js";
|
|
86
86
|
import { revertStaleGeminiMisRewritesMigration } from "./086-revert-stale-gemini-mis-rewrites.js";
|
|
87
|
+
import { memoryRouterBalancedProfileMigration } from "./087-memory-router-balanced-profile.js";
|
|
87
88
|
import { migrateToWorkspaceVolumeMigration } from "./migrate-to-workspace-volume.js";
|
|
88
89
|
import type { WorkspaceMigration } from "./types.js";
|
|
89
90
|
|
|
@@ -179,4 +180,5 @@ export const WORKSPACE_MIGRATIONS: WorkspaceMigration[] = [
|
|
|
179
180
|
removeLegacySkillsIndexMigration,
|
|
180
181
|
memoryV2Bm25BReembedDisabledV2PagesMigration,
|
|
181
182
|
revertStaleGeminiMisRewritesMigration,
|
|
183
|
+
memoryRouterBalancedProfileMigration,
|
|
182
184
|
];
|