@vellumai/assistant 0.4.45 → 0.4.48
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 +6 -6
- package/docs/architecture/memory.md +1 -1
- package/docs/architecture/scheduling.md +2 -3
- package/docs/architecture/security.md +5 -5
- package/docs/trusted-contact-access.md +5 -6
- package/package.json +4 -1
- package/src/__tests__/avatar-e2e.test.ts +18 -219
- package/src/__tests__/avatar-generator.test.ts +5 -57
- package/src/__tests__/browser-fill-credential.test.ts +5 -2
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +2 -1
- package/src/__tests__/channel-readiness-routes.test.ts +20 -19
- package/src/__tests__/cli.test.ts +23 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +23 -22
- package/src/__tests__/credential-broker-server-use.test.ts +22 -21
- package/src/__tests__/credential-broker.test.ts +2 -1
- package/src/__tests__/credential-metadata-store.test.ts +240 -18
- package/src/__tests__/credential-resolve.test.ts +5 -4
- package/src/__tests__/credential-security-e2e.test.ts +8 -8
- package/src/__tests__/credential-security-invariants.test.ts +104 -7
- package/src/__tests__/credential-vault-unit.test.ts +22 -20
- package/src/__tests__/credential-vault.test.ts +284 -12
- package/src/__tests__/credentials-cli.test.ts +11 -6
- package/src/__tests__/gateway-only-enforcement.test.ts +4 -2
- package/src/__tests__/gemini-image-service.test.ts +75 -45
- package/src/__tests__/gemini-provider.test.ts +9 -6
- package/src/__tests__/guardian-action-conversation-turn.test.ts +1 -33
- package/src/__tests__/guardian-action-copy-generator.test.ts +0 -20
- package/src/__tests__/guardian-action-followup-executor.test.ts +1 -28
- package/src/__tests__/guardian-action-followup-store.test.ts +1 -1
- package/src/__tests__/guardian-grant-minting.test.ts +35 -0
- package/src/__tests__/integration-status.test.ts +53 -21
- package/src/__tests__/managed-proxy-context.test.ts +5 -3
- package/src/__tests__/media-generate-image.test.ts +63 -2
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -3
- package/src/__tests__/messaging-send-tool.test.ts +4 -6
- package/src/__tests__/provider-fail-open-selection.test.ts +3 -1
- package/src/__tests__/provider-managed-proxy-integration.test.ts +70 -6
- package/src/__tests__/schedule-store.test.ts +1 -1
- package/src/__tests__/schema-transforms.test.ts +226 -0
- package/src/__tests__/script-proxy-injection-runtime.test.ts +23 -13
- package/src/__tests__/script-proxy-policy-runtime.test.ts +1 -1
- package/src/__tests__/script-proxy-session-manager.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +5 -3
- package/src/__tests__/session-messaging-secret-redirect.test.ts +5 -4
- package/src/__tests__/skills-uninstall.test.ts +2 -2
- package/src/__tests__/skills.test.ts +0 -9
- package/src/__tests__/slack-channel-config.test.ts +9 -8
- package/src/__tests__/slack-share-routes.test.ts +11 -6
- package/src/__tests__/telegram-bot-username-resolution.test.ts +3 -0
- package/src/__tests__/twilio-config.test.ts +2 -1
- package/src/__tests__/twilio-provider.test.ts +4 -2
- package/src/__tests__/twilio-routes.test.ts +5 -4
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
- package/src/approvals/AGENTS.md +1 -1
- package/src/calls/call-domain.ts +7 -4
- package/src/calls/twilio-config.ts +2 -1
- package/src/calls/twilio-provider.ts +2 -1
- package/src/calls/twilio-rest.ts +2 -2
- package/src/cli/commands/browser-relay.ts +40 -15
- package/src/cli/commands/credentials.ts +9 -8
- package/src/cli/commands/oauth.ts +1 -1
- package/src/cli.ts +3 -2
- package/src/config/bundled-skills/claude-code/TOOLS.json +0 -4
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +29 -32
- package/src/config/bundled-skills/gmail/SKILL.md +4 -4
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +54 -61
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +25 -28
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +14 -17
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +39 -44
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +61 -58
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +50 -49
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +11 -13
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +148 -146
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +4 -7
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +175 -173
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +4 -7
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +71 -76
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +32 -38
- package/src/config/bundled-skills/google-calendar/SKILL.md +2 -2
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +70 -29
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +9 -10
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +5 -6
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +4 -5
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +14 -15
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +37 -37
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +4 -9
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +24 -3
- package/src/config/bundled-skills/messaging/SKILL.md +6 -6
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +62 -63
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +15 -16
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +6 -7
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +14 -15
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +128 -128
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +33 -34
- package/src/config/bundled-skills/messaging/tools/shared.ts +11 -11
- package/src/config/bundled-skills/notifications/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +5 -5
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/skill-management/SKILL.md +1 -1
- package/src/config/bundled-skills/slack/tools/shared.ts +4 -10
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +15 -16
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +95 -92
- package/src/config/loader.ts +6 -0
- package/src/daemon/computer-use-session.ts +7 -1
- package/src/daemon/guardian-action-generators.ts +4 -5
- package/src/daemon/handlers/config-slack-channel.ts +37 -20
- package/src/daemon/handlers/config-telegram.ts +33 -20
- package/src/daemon/lifecycle.ts +9 -1
- package/src/daemon/message-types/integrations.ts +1 -0
- package/src/daemon/ride-shotgun-handler.ts +3 -1
- package/src/daemon/session-messaging.ts +3 -1
- package/src/daemon/session-tool-setup.ts +18 -2
- package/src/daemon/session.ts +1 -1
- package/src/email/providers/index.ts +2 -1
- package/src/instrument.ts +15 -1
- package/src/media/app-icon-generator.ts +30 -4
- package/src/media/avatar-router.ts +28 -62
- package/src/media/gemini-image-service.ts +28 -2
- package/src/memory/canonical-guardian-store.ts +1 -1
- package/src/memory/guardian-action-store.ts +1 -1
- package/src/memory/schema/guardian.ts +1 -1
- package/src/messaging/provider.ts +16 -10
- package/src/messaging/providers/gmail/adapter.ts +40 -23
- package/src/messaging/providers/gmail/client.ts +203 -122
- package/src/messaging/providers/gmail/people-client.ts +26 -18
- package/src/messaging/providers/slack/adapter.ts +29 -19
- package/src/messaging/providers/slack/client.ts +265 -78
- package/src/messaging/providers/telegram-bot/adapter.ts +5 -4
- package/src/messaging/providers/whatsapp/adapter.ts +6 -3
- package/src/messaging/registry.ts +2 -1
- package/src/oauth/byo-connection.test.ts +436 -0
- package/src/oauth/byo-connection.ts +112 -0
- package/src/oauth/connect-orchestrator.ts +27 -0
- package/src/oauth/connection-resolver.ts +34 -0
- package/src/oauth/connection.ts +38 -0
- package/src/oauth/platform-connection.test.ts +163 -0
- package/src/oauth/platform-connection.ts +110 -0
- package/src/oauth/provider-base-urls.ts +21 -0
- package/src/oauth/provider-profiles.ts +1 -1
- package/src/oauth/token-persistence.ts +20 -20
- package/src/permissions/checker.ts +6 -1
- package/src/prompts/system-prompt.ts +52 -15
- package/src/prompts/templates/BOOTSTRAP.md +1 -1
- package/src/providers/gemini/client.ts +15 -6
- package/src/providers/managed-proxy/constants.ts +2 -2
- package/src/providers/managed-proxy/context.ts +5 -1
- package/src/providers/ratelimit.ts +17 -0
- package/src/providers/registry.ts +2 -2
- package/src/runtime/AGENTS.md +18 -1
- package/src/runtime/auth/route-policy.ts +1 -0
- package/src/runtime/channel-invite-transports/telegram.ts +2 -1
- package/src/runtime/channel-readiness-service.ts +168 -195
- package/src/runtime/channel-readiness-types.ts +4 -0
- package/src/runtime/guardian-action-conversation-turn.ts +1 -3
- package/src/runtime/guardian-action-followup-executor.ts +1 -2
- package/src/runtime/guardian-action-message-composer.ts +3 -23
- package/src/runtime/http-server.ts +9 -4
- package/src/runtime/http-types.ts +0 -1
- package/src/runtime/middleware/rate-limiter.ts +74 -20
- package/src/runtime/middleware/twilio-validation.ts +1 -3
- package/src/runtime/routes/channel-readiness-routes.ts +2 -0
- package/src/runtime/routes/diagnostics-routes.ts +11 -9
- package/src/runtime/routes/guardian-approval-interception.ts +20 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +71 -25
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -5
- package/src/runtime/routes/integrations/slack/share.ts +3 -2
- package/src/runtime/routes/integrations/twilio.ts +6 -5
- package/src/runtime/routes/secret-routes.ts +3 -2
- package/src/runtime/routes/settings-routes.ts +75 -17
- package/src/runtime/telegram-streaming-delivery.test.ts +132 -0
- package/src/runtime/telegram-streaming-delivery.ts +11 -1
- package/src/schedule/integration-status.ts +5 -4
- package/src/security/credential-key.ts +170 -0
- package/src/security/token-manager.ts +36 -7
- package/src/tools/apps/definitions.ts +0 -5
- package/src/tools/assets/materialize.ts +0 -5
- package/src/tools/assets/search.ts +0 -5
- package/src/tools/browser/headless-browser.ts +1 -67
- package/src/tools/claude-code/claude-code.ts +0 -5
- package/src/tools/computer-use/request-computer-control.ts +0 -5
- package/src/tools/credentials/broker.ts +6 -4
- package/src/tools/credentials/metadata-store.ts +72 -20
- package/src/tools/credentials/resolve.ts +2 -1
- package/src/tools/credentials/vault.ts +77 -16
- package/src/tools/filesystem/edit.ts +1 -6
- package/src/tools/filesystem/read.ts +0 -5
- package/src/tools/filesystem/write.ts +1 -6
- package/src/tools/host-filesystem/edit.ts +1 -6
- package/src/tools/host-filesystem/read.ts +1 -6
- package/src/tools/host-filesystem/write.ts +1 -6
- package/src/tools/mcp/mcp-tool-factory.ts +18 -1
- package/src/tools/memory/definitions.ts +0 -5
- package/src/tools/network/web-fetch.ts +0 -5
- package/src/tools/network/web-search.ts +0 -5
- package/src/tools/schema-transforms.ts +99 -0
- package/src/tools/skills/load.ts +0 -5
- package/src/tools/swarm/delegate.ts +0 -5
- package/src/tools/system/avatar-generator.ts +3 -44
- package/src/tools/ui-surface/definitions.ts +0 -15
- package/src/tools/watch/screen-watch.ts +0 -5
- package/src/version.ts +10 -0
- package/src/watcher/providers/github.ts +51 -52
- package/src/watcher/providers/gmail.ts +88 -80
- package/src/watcher/providers/google-calendar.ts +93 -86
- package/src/watcher/providers/linear.ts +87 -93
- package/src/__tests__/avatar-router.test.ts +0 -149
- package/src/__tests__/managed-avatar-client.test.ts +0 -337
- package/src/config/bundled-skills/doordash/SKILL.md +0 -170
- package/src/config/bundled-skills/doordash/__tests__/doordash-client.test.ts +0 -205
- package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +0 -74
- package/src/config/bundled-skills/doordash/doordash-cli.ts +0 -1081
- package/src/config/bundled-skills/doordash/doordash-entry.ts +0 -22
- package/src/config/bundled-skills/doordash/lib/cart-queries.ts +0 -787
- package/src/config/bundled-skills/doordash/lib/client.ts +0 -1069
- package/src/config/bundled-skills/doordash/lib/order-queries.ts +0 -85
- package/src/config/bundled-skills/doordash/lib/queries.ts +0 -28
- package/src/config/bundled-skills/doordash/lib/query-extractor.ts +0 -94
- package/src/config/bundled-skills/doordash/lib/search-queries.ts +0 -203
- package/src/config/bundled-skills/doordash/lib/session.ts +0 -96
- package/src/config/bundled-skills/doordash/lib/shared/errors.ts +0 -61
- package/src/config/bundled-skills/doordash/lib/shared/network-recorder.ts +0 -380
- package/src/config/bundled-skills/doordash/lib/shared/platform.ts +0 -55
- package/src/config/bundled-skills/doordash/lib/shared/recording-store.ts +0 -43
- package/src/config/bundled-skills/doordash/lib/shared/recording-types.ts +0 -49
- package/src/config/bundled-skills/doordash/lib/shared/truncate.ts +0 -6
- package/src/config/bundled-skills/doordash/lib/store-queries.ts +0 -246
- package/src/config/bundled-skills/doordash/lib/types.ts +0 -367
- package/src/media/avatar-types.ts +0 -53
- package/src/media/managed-avatar-client.ts +0 -225
|
@@ -23,6 +23,10 @@ import type {
|
|
|
23
23
|
import { allComputerUseTools } from "../tools/computer-use/definitions.js";
|
|
24
24
|
import { ToolExecutor } from "../tools/executor.js";
|
|
25
25
|
import { getTool, registerSkillTools } from "../tools/registry.js";
|
|
26
|
+
import {
|
|
27
|
+
injectReasonField,
|
|
28
|
+
REASON_SKIP_SET,
|
|
29
|
+
} from "../tools/schema-transforms.js";
|
|
26
30
|
import type { Tool, ToolExecutionResult } from "../tools/types.js";
|
|
27
31
|
import { allUiSurfaceTools } from "../tools/ui-surface/definitions.js";
|
|
28
32
|
import { getLogger } from "../util/logger.js";
|
|
@@ -581,6 +585,8 @@ export class ComputerUseSession {
|
|
|
581
585
|
},
|
|
582
586
|
};
|
|
583
587
|
|
|
588
|
+
const toolDefsWithReason = injectReasonField(toolDefs, REASON_SKIP_SET);
|
|
589
|
+
|
|
584
590
|
const cuConfig = getConfig();
|
|
585
591
|
const agentLoop = new AgentLoop(
|
|
586
592
|
compactingProvider,
|
|
@@ -590,7 +596,7 @@ export class ComputerUseSession {
|
|
|
590
596
|
maxInputTokens: cuConfig.contextWindow.maxInputTokens,
|
|
591
597
|
toolChoice: { type: "any" },
|
|
592
598
|
},
|
|
593
|
-
|
|
599
|
+
toolDefsWithReason,
|
|
594
600
|
toolExecutor,
|
|
595
601
|
);
|
|
596
602
|
|
|
@@ -83,8 +83,8 @@ const FOLLOWUP_CONVERSATION_MAX_TOKENS = 300;
|
|
|
83
83
|
const FOLLOWUP_CONVERSATION_SYSTEM_PROMPT =
|
|
84
84
|
"You are an assistant helping route a guardian's reply to a post-timeout follow-up message. " +
|
|
85
85
|
"A voice caller asked a question, but the call timed out before the guardian could answer. " +
|
|
86
|
-
"The guardian has now replied late, and was asked whether they want to call the caller back
|
|
87
|
-
"
|
|
86
|
+
"The guardian has now replied late, and was asked whether they want to call the caller back " +
|
|
87
|
+
"or skip it. " +
|
|
88
88
|
"Analyze the guardian's latest reply to determine their intent. " +
|
|
89
89
|
"When uncertain, default to keep_pending and ask a clarifying question. " +
|
|
90
90
|
"Always provide a natural, helpful reply along with your decision.";
|
|
@@ -101,10 +101,10 @@ const FOLLOWUP_CONVERSATION_TOOL_SCHEMA = {
|
|
|
101
101
|
properties: {
|
|
102
102
|
disposition: {
|
|
103
103
|
type: "string",
|
|
104
|
-
enum: ["call_back", "
|
|
104
|
+
enum: ["call_back", "decline", "keep_pending"],
|
|
105
105
|
description:
|
|
106
106
|
"The guardian's intent: call_back to call the original caller, " +
|
|
107
|
-
"
|
|
107
|
+
"decline to skip the follow-up, " +
|
|
108
108
|
"keep_pending if the intent is unclear (ask for clarification).",
|
|
109
109
|
},
|
|
110
110
|
replyText: {
|
|
@@ -118,7 +118,6 @@ const FOLLOWUP_CONVERSATION_TOOL_SCHEMA = {
|
|
|
118
118
|
|
|
119
119
|
const VALID_FOLLOWUP_DISPOSITIONS: ReadonlySet<string> = new Set([
|
|
120
120
|
"call_back",
|
|
121
|
-
"message_back",
|
|
122
121
|
"decline",
|
|
123
122
|
"keep_pending",
|
|
124
123
|
]);
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
saveRawConfig,
|
|
6
6
|
setNestedValue,
|
|
7
7
|
} from "../../config/loader.js";
|
|
8
|
+
import { credentialKey } from "../../security/credential-key.js";
|
|
8
9
|
import {
|
|
9
10
|
deleteSecureKeyAsync,
|
|
10
11
|
getSecureKey,
|
|
@@ -34,8 +35,12 @@ export interface SlackChannelConfigResult {
|
|
|
34
35
|
// -- Business logic --
|
|
35
36
|
|
|
36
37
|
export function getSlackChannelConfig(): SlackChannelConfigResult {
|
|
37
|
-
const hasBotToken = !!getSecureKey(
|
|
38
|
-
|
|
38
|
+
const hasBotToken = !!getSecureKey(
|
|
39
|
+
credentialKey("slack_channel", "bot_token"),
|
|
40
|
+
);
|
|
41
|
+
const hasAppToken = !!getSecureKey(
|
|
42
|
+
credentialKey("slack_channel", "app_token"),
|
|
43
|
+
);
|
|
39
44
|
const { teamId, teamName, botUserId, botUsername } = getConfig().slack;
|
|
40
45
|
return {
|
|
41
46
|
success: true,
|
|
@@ -79,10 +84,10 @@ export async function setSlackChannelConfig(
|
|
|
79
84
|
};
|
|
80
85
|
if (!data.ok) {
|
|
81
86
|
const storedBotToken = !!getSecureKey(
|
|
82
|
-
"
|
|
87
|
+
credentialKey("slack_channel", "bot_token"),
|
|
83
88
|
);
|
|
84
89
|
const storedAppToken = !!getSecureKey(
|
|
85
|
-
"
|
|
90
|
+
credentialKey("slack_channel", "app_token"),
|
|
86
91
|
);
|
|
87
92
|
return {
|
|
88
93
|
success: false,
|
|
@@ -103,10 +108,10 @@ export async function setSlackChannelConfig(
|
|
|
103
108
|
} catch (err) {
|
|
104
109
|
const message = err instanceof Error ? err.message : String(err);
|
|
105
110
|
const storedBotToken = !!getSecureKey(
|
|
106
|
-
"
|
|
111
|
+
credentialKey("slack_channel", "bot_token"),
|
|
107
112
|
);
|
|
108
113
|
const storedAppToken = !!getSecureKey(
|
|
109
|
-
"
|
|
114
|
+
credentialKey("slack_channel", "app_token"),
|
|
110
115
|
);
|
|
111
116
|
return {
|
|
112
117
|
success: false,
|
|
@@ -118,15 +123,15 @@ export async function setSlackChannelConfig(
|
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
const stored = await setSecureKeyAsync(
|
|
121
|
-
"
|
|
126
|
+
credentialKey("slack_channel", "bot_token"),
|
|
122
127
|
botToken,
|
|
123
128
|
);
|
|
124
129
|
if (!stored) {
|
|
125
130
|
const storedBotToken = !!getSecureKey(
|
|
126
|
-
"
|
|
131
|
+
credentialKey("slack_channel", "bot_token"),
|
|
127
132
|
);
|
|
128
133
|
const storedAppToken = !!getSecureKey(
|
|
129
|
-
"
|
|
134
|
+
credentialKey("slack_channel", "app_token"),
|
|
130
135
|
);
|
|
131
136
|
return {
|
|
132
137
|
success: false,
|
|
@@ -161,10 +166,10 @@ export async function setSlackChannelConfig(
|
|
|
161
166
|
if (appToken) {
|
|
162
167
|
if (!appToken.startsWith("xapp-")) {
|
|
163
168
|
const storedBotToken = !!getSecureKey(
|
|
164
|
-
"
|
|
169
|
+
credentialKey("slack_channel", "bot_token"),
|
|
165
170
|
);
|
|
166
171
|
const storedAppToken = !!getSecureKey(
|
|
167
|
-
"
|
|
172
|
+
credentialKey("slack_channel", "app_token"),
|
|
168
173
|
);
|
|
169
174
|
return {
|
|
170
175
|
success: false,
|
|
@@ -176,15 +181,15 @@ export async function setSlackChannelConfig(
|
|
|
176
181
|
}
|
|
177
182
|
|
|
178
183
|
const stored = await setSecureKeyAsync(
|
|
179
|
-
"
|
|
184
|
+
credentialKey("slack_channel", "app_token"),
|
|
180
185
|
appToken,
|
|
181
186
|
);
|
|
182
187
|
if (!stored) {
|
|
183
188
|
const storedBotToken = !!getSecureKey(
|
|
184
|
-
"
|
|
189
|
+
credentialKey("slack_channel", "bot_token"),
|
|
185
190
|
);
|
|
186
191
|
const storedAppToken = !!getSecureKey(
|
|
187
|
-
"
|
|
192
|
+
credentialKey("slack_channel", "app_token"),
|
|
188
193
|
);
|
|
189
194
|
return {
|
|
190
195
|
success: false,
|
|
@@ -198,8 +203,12 @@ export async function setSlackChannelConfig(
|
|
|
198
203
|
upsertCredentialMetadata("slack_channel", "app_token", {});
|
|
199
204
|
}
|
|
200
205
|
|
|
201
|
-
const hasBotToken = !!getSecureKey(
|
|
202
|
-
|
|
206
|
+
const hasBotToken = !!getSecureKey(
|
|
207
|
+
credentialKey("slack_channel", "bot_token"),
|
|
208
|
+
);
|
|
209
|
+
const hasAppToken = !!getSecureKey(
|
|
210
|
+
credentialKey("slack_channel", "app_token"),
|
|
211
|
+
);
|
|
203
212
|
|
|
204
213
|
if (hasBotToken && !hasAppToken) {
|
|
205
214
|
warning =
|
|
@@ -220,12 +229,20 @@ export async function setSlackChannelConfig(
|
|
|
220
229
|
}
|
|
221
230
|
|
|
222
231
|
export async function clearSlackChannelConfig(): Promise<SlackChannelConfigResult> {
|
|
223
|
-
const r1 = await deleteSecureKeyAsync(
|
|
224
|
-
|
|
232
|
+
const r1 = await deleteSecureKeyAsync(
|
|
233
|
+
credentialKey("slack_channel", "bot_token"),
|
|
234
|
+
);
|
|
235
|
+
const r2 = await deleteSecureKeyAsync(
|
|
236
|
+
credentialKey("slack_channel", "app_token"),
|
|
237
|
+
);
|
|
225
238
|
|
|
226
239
|
if (r1 === "error" || r2 === "error") {
|
|
227
|
-
const hasBotToken = !!getSecureKey(
|
|
228
|
-
|
|
240
|
+
const hasBotToken = !!getSecureKey(
|
|
241
|
+
credentialKey("slack_channel", "bot_token"),
|
|
242
|
+
);
|
|
243
|
+
const hasAppToken = !!getSecureKey(
|
|
244
|
+
credentialKey("slack_channel", "app_token"),
|
|
245
|
+
);
|
|
229
246
|
return {
|
|
230
247
|
success: false,
|
|
231
248
|
hasBotToken,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
registerCallbackRoute,
|
|
9
9
|
shouldUsePlatformCallbacks,
|
|
10
10
|
} from "../../inbound/platform-callback-registration.js";
|
|
11
|
+
import { credentialKey } from "../../security/credential-key.js";
|
|
11
12
|
import {
|
|
12
13
|
deleteSecureKeyAsync,
|
|
13
14
|
getSecureKey,
|
|
@@ -60,8 +61,10 @@ export type TelegramConfigResult = Omit<TelegramConfigResponse, "type">;
|
|
|
60
61
|
// -- Extracted business logic functions --
|
|
61
62
|
|
|
62
63
|
export function getTelegramConfig(): TelegramConfigResult {
|
|
63
|
-
const hasBotToken = !!getSecureKey("
|
|
64
|
-
const hasWebhookSecret = !!getSecureKey(
|
|
64
|
+
const hasBotToken = !!getSecureKey(credentialKey("telegram", "bot_token"));
|
|
65
|
+
const hasWebhookSecret = !!getSecureKey(
|
|
66
|
+
credentialKey("telegram", "webhook_secret"),
|
|
67
|
+
);
|
|
65
68
|
const botUsername = getTelegramBotUsername();
|
|
66
69
|
return {
|
|
67
70
|
success: true,
|
|
@@ -79,7 +82,7 @@ export async function setTelegramConfig(
|
|
|
79
82
|
// Track provenance so we only rollback tokens that were freshly provided.
|
|
80
83
|
const isNewToken = !!botToken;
|
|
81
84
|
const resolvedToken =
|
|
82
|
-
botToken || getSecureKey("
|
|
85
|
+
botToken || getSecureKey(credentialKey("telegram", "bot_token"));
|
|
83
86
|
if (!resolvedToken) {
|
|
84
87
|
return {
|
|
85
88
|
success: false,
|
|
@@ -133,7 +136,7 @@ export async function setTelegramConfig(
|
|
|
133
136
|
|
|
134
137
|
// Store bot token securely (async — writes broker + encrypted store)
|
|
135
138
|
const stored = await setSecureKeyAsync(
|
|
136
|
-
"
|
|
139
|
+
credentialKey("telegram", "bot_token"),
|
|
137
140
|
resolvedToken,
|
|
138
141
|
);
|
|
139
142
|
if (!stored) {
|
|
@@ -156,12 +159,14 @@ export async function setTelegramConfig(
|
|
|
156
159
|
invalidateConfigCache();
|
|
157
160
|
|
|
158
161
|
// Ensure webhook secret exists (generate if missing)
|
|
159
|
-
let hasWebhookSecret = !!getSecureKey(
|
|
162
|
+
let hasWebhookSecret = !!getSecureKey(
|
|
163
|
+
credentialKey("telegram", "webhook_secret"),
|
|
164
|
+
);
|
|
160
165
|
if (!hasWebhookSecret) {
|
|
161
166
|
const { randomUUID } = await import("node:crypto");
|
|
162
167
|
const webhookSecret = randomUUID();
|
|
163
168
|
const secretStored = await setSecureKeyAsync(
|
|
164
|
-
"
|
|
169
|
+
credentialKey("telegram", "webhook_secret"),
|
|
165
170
|
webhookSecret,
|
|
166
171
|
);
|
|
167
172
|
if (secretStored) {
|
|
@@ -172,7 +177,7 @@ export async function setTelegramConfig(
|
|
|
172
177
|
// When the token came from secure storage it was already valid
|
|
173
178
|
// configuration; deleting it would destroy working state.
|
|
174
179
|
if (isNewToken) {
|
|
175
|
-
await deleteSecureKeyAsync("
|
|
180
|
+
await deleteSecureKeyAsync(credentialKey("telegram", "bot_token"));
|
|
176
181
|
deleteCredentialMetadata("telegram", "bot_token");
|
|
177
182
|
}
|
|
178
183
|
// Always revert the config write — the botUsername was written
|
|
@@ -222,7 +227,7 @@ export async function clearTelegramConfig(): Promise<TelegramConfigResult> {
|
|
|
222
227
|
// The gateway reconcile short-circuits when credentials are absent,
|
|
223
228
|
// so we must call the Telegram API directly while the token is still
|
|
224
229
|
// available.
|
|
225
|
-
const botToken = getSecureKey("
|
|
230
|
+
const botToken = getSecureKey(credentialKey("telegram", "bot_token"));
|
|
226
231
|
if (botToken) {
|
|
227
232
|
try {
|
|
228
233
|
await fetch(`https://api.telegram.org/bot${botToken}/deleteWebhook`);
|
|
@@ -234,13 +239,15 @@ export async function clearTelegramConfig(): Promise<TelegramConfigResult> {
|
|
|
234
239
|
}
|
|
235
240
|
}
|
|
236
241
|
|
|
237
|
-
const r1 = await deleteSecureKeyAsync("
|
|
238
|
-
const r2 = await deleteSecureKeyAsync(
|
|
242
|
+
const r1 = await deleteSecureKeyAsync(credentialKey("telegram", "bot_token"));
|
|
243
|
+
const r2 = await deleteSecureKeyAsync(
|
|
244
|
+
credentialKey("telegram", "webhook_secret"),
|
|
245
|
+
);
|
|
239
246
|
|
|
240
247
|
if (r1 === "error" || r2 === "error") {
|
|
241
|
-
const hasBotToken = !!getSecureKey("
|
|
248
|
+
const hasBotToken = !!getSecureKey(credentialKey("telegram", "bot_token"));
|
|
242
249
|
const hasWebhookSecret = !!getSecureKey(
|
|
243
|
-
"
|
|
250
|
+
credentialKey("telegram", "webhook_secret"),
|
|
244
251
|
);
|
|
245
252
|
return {
|
|
246
253
|
success: false,
|
|
@@ -272,7 +279,7 @@ export async function clearTelegramConfig(): Promise<TelegramConfigResult> {
|
|
|
272
279
|
export async function setTelegramCommands(
|
|
273
280
|
commands?: Array<{ command: string; description: string }>,
|
|
274
281
|
): Promise<TelegramConfigResult> {
|
|
275
|
-
const storedToken = getSecureKey("
|
|
282
|
+
const storedToken = getSecureKey(credentialKey("telegram", "bot_token"));
|
|
276
283
|
if (!storedToken) {
|
|
277
284
|
return {
|
|
278
285
|
success: false,
|
|
@@ -302,8 +309,10 @@ export async function setTelegramCommands(
|
|
|
302
309
|
return {
|
|
303
310
|
success: false,
|
|
304
311
|
hasBotToken: true,
|
|
305
|
-
connected: !!getSecureKey("
|
|
306
|
-
hasWebhookSecret: !!getSecureKey(
|
|
312
|
+
connected: !!getSecureKey(credentialKey("telegram", "webhook_secret")),
|
|
313
|
+
hasWebhookSecret: !!getSecureKey(
|
|
314
|
+
credentialKey("telegram", "webhook_secret"),
|
|
315
|
+
),
|
|
307
316
|
error: `Failed to set bot commands: ${body}`,
|
|
308
317
|
};
|
|
309
318
|
}
|
|
@@ -312,14 +321,18 @@ export async function setTelegramCommands(
|
|
|
312
321
|
return {
|
|
313
322
|
success: false,
|
|
314
323
|
hasBotToken: true,
|
|
315
|
-
connected: !!getSecureKey("
|
|
316
|
-
hasWebhookSecret: !!getSecureKey(
|
|
324
|
+
connected: !!getSecureKey(credentialKey("telegram", "webhook_secret")),
|
|
325
|
+
hasWebhookSecret: !!getSecureKey(
|
|
326
|
+
credentialKey("telegram", "webhook_secret"),
|
|
327
|
+
),
|
|
317
328
|
error: `Failed to set bot commands: ${message}`,
|
|
318
329
|
};
|
|
319
330
|
}
|
|
320
331
|
|
|
321
|
-
const hasBotToken = !!getSecureKey("
|
|
322
|
-
const hasWebhookSecret = !!getSecureKey(
|
|
332
|
+
const hasBotToken = !!getSecureKey(credentialKey("telegram", "bot_token"));
|
|
333
|
+
const hasWebhookSecret = !!getSecureKey(
|
|
334
|
+
credentialKey("telegram", "webhook_secret"),
|
|
335
|
+
);
|
|
323
336
|
return {
|
|
324
337
|
success: true,
|
|
325
338
|
hasBotToken,
|
|
@@ -401,4 +414,4 @@ export async function handleTelegramConfig(
|
|
|
401
414
|
error: message,
|
|
402
415
|
});
|
|
403
416
|
}
|
|
404
|
-
}
|
|
417
|
+
}
|
package/src/daemon/lifecycle.ts
CHANGED
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
import { ensureVellumGuardianBinding } from "../runtime/guardian-vellum-migration.js";
|
|
55
55
|
import { RuntimeHttpServer } from "../runtime/http-server.js";
|
|
56
56
|
import { startScheduler } from "../schedule/scheduler.js";
|
|
57
|
+
import { migrateKeys } from "../security/credential-key.js";
|
|
57
58
|
import { watchSessions } from "../tools/watch/watch-state.js";
|
|
58
59
|
import { getLogger, initLogger } from "../util/logger.js";
|
|
59
60
|
import {
|
|
@@ -136,6 +137,11 @@ export async function runDaemon(): Promise<void> {
|
|
|
136
137
|
|
|
137
138
|
ensureDataDir();
|
|
138
139
|
|
|
140
|
+
// Migrate legacy colon-delimited credential keys to the new
|
|
141
|
+
// slash-delimited format. Must run after ensureDataDir() so the
|
|
142
|
+
// secure key store is available, and before any credential reads.
|
|
143
|
+
migrateKeys();
|
|
144
|
+
|
|
139
145
|
// Load (or generate + persist) the auth signing key so tokens survive
|
|
140
146
|
// daemon restarts. Must happen after ensureDataDir() creates the
|
|
141
147
|
// protected directory.
|
|
@@ -193,7 +199,9 @@ export async function runDaemon(): Promise<void> {
|
|
|
193
199
|
const httpTokenPath = join(getRootDir(), "http-token");
|
|
194
200
|
writeFileSync(httpTokenPath, credentials.accessToken, { mode: 0o600 });
|
|
195
201
|
chmodSync(httpTokenPath, 0o600);
|
|
196
|
-
log.info(
|
|
202
|
+
log.info(
|
|
203
|
+
"Daemon startup: CLI edge token written to credential store and http-token",
|
|
204
|
+
);
|
|
197
205
|
} else {
|
|
198
206
|
log.warn("No guardian principal available — CLI edge token not written");
|
|
199
207
|
}
|
|
@@ -501,13 +501,15 @@ async function finalizeLearnRecording(
|
|
|
501
501
|
// Save cookies to the encrypted credential store (keyed by target domain)
|
|
502
502
|
// so they don't need to be persisted in the plaintext recording file.
|
|
503
503
|
if (session.targetDomain && cookies.length > 0) {
|
|
504
|
+
const { credentialKey: credKey } =
|
|
505
|
+
await import("../security/credential-key.js");
|
|
504
506
|
const { setSecureKeyAsync } = await import("../security/secure-keys.js");
|
|
505
507
|
const { upsertCredentialMetadata } =
|
|
506
508
|
await import("../tools/credentials/metadata-store.js");
|
|
507
509
|
|
|
508
510
|
const service = session.targetDomain;
|
|
509
511
|
const field = "session:cookies";
|
|
510
|
-
const storageKey =
|
|
512
|
+
const storageKey = credKey(service, field);
|
|
511
513
|
const stored = await setSecureKeyAsync(
|
|
512
514
|
storageKey,
|
|
513
515
|
JSON.stringify(cookies),
|
|
@@ -446,7 +446,9 @@ export function redirectToSecurePrompt(
|
|
|
446
446
|
"Ingress redirect: transient credential injected",
|
|
447
447
|
);
|
|
448
448
|
} else {
|
|
449
|
-
const
|
|
449
|
+
const { credentialKey: credKey } =
|
|
450
|
+
await import("../security/credential-key.js");
|
|
451
|
+
const key = credKey(target.service, target.field);
|
|
450
452
|
const stored = await setSecureKeyAsync(key, result.value);
|
|
451
453
|
if (stored) {
|
|
452
454
|
try {
|
|
@@ -31,6 +31,10 @@ import {
|
|
|
31
31
|
getAllToolDefinitions,
|
|
32
32
|
getMcpToolDefinitions,
|
|
33
33
|
} from "../tools/registry.js";
|
|
34
|
+
import {
|
|
35
|
+
injectReasonField,
|
|
36
|
+
REASON_SKIP_SET,
|
|
37
|
+
} from "../tools/schema-transforms.js";
|
|
34
38
|
import type {
|
|
35
39
|
ProxyApprovalCallback,
|
|
36
40
|
ProxyApprovalRequest,
|
|
@@ -335,11 +339,23 @@ export function createToolExecutor(
|
|
|
335
339
|
// with the real tool name.
|
|
336
340
|
if (name === "skill_execute") {
|
|
337
341
|
const toolName = typeof input.tool === "string" ? input.tool : "";
|
|
338
|
-
const
|
|
342
|
+
const rawToolInput =
|
|
339
343
|
input.input != null && typeof input.input === "object"
|
|
340
344
|
? (input.input as Record<string, unknown>)
|
|
341
345
|
: {};
|
|
342
346
|
|
|
347
|
+
// Clone to avoid mutating shared input objects
|
|
348
|
+
const toolInput = { ...rawToolInput };
|
|
349
|
+
|
|
350
|
+
// Propagate outer reason when inner input lacks a valid one
|
|
351
|
+
if (
|
|
352
|
+
typeof input.reason === "string" &&
|
|
353
|
+
input.reason &&
|
|
354
|
+
(typeof toolInput.reason !== "string" || toolInput.reason.length === 0)
|
|
355
|
+
) {
|
|
356
|
+
toolInput.reason = input.reason;
|
|
357
|
+
}
|
|
358
|
+
|
|
343
359
|
if (!toolName) {
|
|
344
360
|
return {
|
|
345
361
|
content:
|
|
@@ -663,6 +679,6 @@ export function createResolveToolsCallback(
|
|
|
663
679
|
turnAllowed.add(name);
|
|
664
680
|
}
|
|
665
681
|
ctx.allowedToolNames = turnAllowed;
|
|
666
|
-
return allBaseDefs;
|
|
682
|
+
return injectReasonField(allBaseDefs, REASON_SKIP_SET);
|
|
667
683
|
};
|
|
668
684
|
}
|
package/src/daemon/session.ts
CHANGED
|
@@ -324,7 +324,7 @@ export class Session {
|
|
|
324
324
|
const resolved = {
|
|
325
325
|
systemPrompt: hasSystemPromptOverride
|
|
326
326
|
? systemPrompt
|
|
327
|
-
: buildSystemPrompt(),
|
|
327
|
+
: buildSystemPrompt({ hasNoClient: this.hasNoClient }),
|
|
328
328
|
maxTokens: configuredMaxTokens,
|
|
329
329
|
};
|
|
330
330
|
return resolved;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { getNestedValue, loadRawConfig } from "../../config/loader.js";
|
|
8
|
+
import { credentialKey } from "../../security/credential-key.js";
|
|
8
9
|
import { getSecureKey } from "../../security/secure-keys.js";
|
|
9
10
|
import { ConfigError } from "../../util/errors.js";
|
|
10
11
|
import type { EmailProvider } from "../provider.js";
|
|
@@ -13,7 +14,7 @@ export const SUPPORTED_PROVIDERS = ["agentmail"] as const;
|
|
|
13
14
|
export type SupportedProvider = (typeof SUPPORTED_PROVIDERS)[number];
|
|
14
15
|
|
|
15
16
|
const PROVIDER_KEY_MAP: Record<SupportedProvider, string[]> = {
|
|
16
|
-
agentmail: ["agentmail", "
|
|
17
|
+
agentmail: ["agentmail", credentialKey("agentmail", "api_key")],
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
/**
|
package/src/instrument.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { arch, platform, release } from "node:os";
|
|
2
|
+
|
|
1
3
|
import * as Sentry from "@sentry/node";
|
|
2
4
|
|
|
3
5
|
import { getSentryDsn } from "./config/env.js";
|
|
4
|
-
import { APP_VERSION } from "./version.js";
|
|
6
|
+
import { APP_VERSION, COMMIT_SHA } from "./version.js";
|
|
5
7
|
|
|
6
8
|
/** Patterns that match sensitive data in Sentry event values. */
|
|
7
9
|
const PII_PATTERNS = [
|
|
@@ -42,8 +44,20 @@ export function initSentry(): void {
|
|
|
42
44
|
Sentry.init({
|
|
43
45
|
dsn: getSentryDsn(),
|
|
44
46
|
release: `vellum-assistant@${APP_VERSION}`,
|
|
47
|
+
dist: COMMIT_SHA,
|
|
45
48
|
environment: APP_VERSION === "0.0.0-dev" ? "development" : "production",
|
|
46
49
|
sendDefaultPii: false,
|
|
50
|
+
initialScope: {
|
|
51
|
+
tags: {
|
|
52
|
+
commit: COMMIT_SHA,
|
|
53
|
+
os_platform: platform(),
|
|
54
|
+
os_release: release(),
|
|
55
|
+
os_arch: arch(),
|
|
56
|
+
runtime: "bun",
|
|
57
|
+
runtime_version:
|
|
58
|
+
typeof Bun !== "undefined" ? Bun.version : process.version,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
47
61
|
beforeSend(event) {
|
|
48
62
|
if (event.exception?.values) {
|
|
49
63
|
event.exception.values = event.exception.values.map((ex) => ({
|
|
@@ -11,8 +11,16 @@ import { join } from "node:path";
|
|
|
11
11
|
|
|
12
12
|
import { getConfig } from "../config/loader.js";
|
|
13
13
|
import { getAppsDir } from "../memory/app-store.js";
|
|
14
|
+
import {
|
|
15
|
+
buildManagedBaseUrl,
|
|
16
|
+
resolveManagedProxyContext,
|
|
17
|
+
} from "../providers/managed-proxy/context.js";
|
|
14
18
|
import { getLogger } from "../util/logger.js";
|
|
15
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
generateImage,
|
|
21
|
+
type ImageGenCredentials,
|
|
22
|
+
mapGeminiError,
|
|
23
|
+
} from "./gemini-image-service.js";
|
|
16
24
|
|
|
17
25
|
const log = getLogger("app-icon-generator");
|
|
18
26
|
|
|
@@ -29,8 +37,26 @@ export async function generateAppIcon(
|
|
|
29
37
|
): Promise<void> {
|
|
30
38
|
const config = getConfig();
|
|
31
39
|
const apiKey = config.apiKeys.gemini ?? process.env.GEMINI_API_KEY;
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
|
|
41
|
+
let credentials: ImageGenCredentials | undefined;
|
|
42
|
+
if (apiKey) {
|
|
43
|
+
credentials = { type: "direct", apiKey };
|
|
44
|
+
} else {
|
|
45
|
+
const managedBaseUrl = buildManagedBaseUrl("vertex");
|
|
46
|
+
if (managedBaseUrl) {
|
|
47
|
+
const ctx = resolveManagedProxyContext();
|
|
48
|
+
credentials = {
|
|
49
|
+
type: "managed-proxy",
|
|
50
|
+
assistantApiKey: ctx.assistantApiKey,
|
|
51
|
+
baseUrl: managedBaseUrl,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!credentials) {
|
|
57
|
+
log.debug(
|
|
58
|
+
"No Gemini API key or managed proxy — skipping app icon generation",
|
|
59
|
+
);
|
|
34
60
|
return;
|
|
35
61
|
}
|
|
36
62
|
|
|
@@ -58,7 +84,7 @@ export async function generateAppIcon(
|
|
|
58
84
|
try {
|
|
59
85
|
log.info({ appId, appName }, "Generating app icon via Gemini");
|
|
60
86
|
|
|
61
|
-
const result = await generateImage(
|
|
87
|
+
const result = await generateImage(credentials, {
|
|
62
88
|
prompt,
|
|
63
89
|
mode: "generate",
|
|
64
90
|
model: config.imageGenModel,
|