@vellumai/assistant 0.4.46 → 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 +5 -5
- package/docs/architecture/security.md +5 -5
- package/package.json +1 -1
- 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 -6
- 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__/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/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 -1
- 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/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 +26 -3
- package/src/media/gemini-image-service.ts +28 -2
- 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 +5 -1
- package/src/prompts/system-prompt.ts +49 -12
- 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 +17 -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 -1
- 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/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/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 +0 -5
- 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
|
@@ -2,7 +2,7 @@ import type {
|
|
|
2
2
|
ToolContext,
|
|
3
3
|
ToolExecutionResult,
|
|
4
4
|
} from "../../../../tools/types.js";
|
|
5
|
-
import { err, ok, resolveProvider
|
|
5
|
+
import { err, getProviderConnection, ok, resolveProvider } from "./shared.js";
|
|
6
6
|
|
|
7
7
|
export async function run(
|
|
8
8
|
input: Record<string, unknown>,
|
|
@@ -23,47 +23,46 @@ export async function run(
|
|
|
23
23
|
);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (result.senders.length === 0) {
|
|
34
|
-
return ok(
|
|
35
|
-
JSON.stringify({
|
|
36
|
-
senders: [],
|
|
37
|
-
total_scanned: result.totalScanned,
|
|
38
|
-
query_used: result.queryUsed,
|
|
39
|
-
...(result.truncated ? { truncated: true } : {}),
|
|
40
|
-
message:
|
|
41
|
-
"No emails found matching the query. Try broadening the search (e.g. remove category filter or extend date range).",
|
|
42
|
-
}),
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Map to snake_case output format for LLM consumption
|
|
47
|
-
const senders = result.senders.map((s) => ({
|
|
48
|
-
id: s.id,
|
|
49
|
-
display_name: s.displayName,
|
|
50
|
-
email: s.email,
|
|
51
|
-
message_count: s.messageCount,
|
|
52
|
-
has_unsubscribe: s.hasUnsubscribe,
|
|
53
|
-
newest_message_id: s.newestMessageId,
|
|
54
|
-
search_query: s.searchQuery,
|
|
55
|
-
}));
|
|
26
|
+
const conn = getProviderConnection(provider);
|
|
27
|
+
const result = await provider.senderDigest!(conn, query, {
|
|
28
|
+
maxMessages,
|
|
29
|
+
maxSenders,
|
|
30
|
+
pageToken,
|
|
31
|
+
});
|
|
56
32
|
|
|
33
|
+
if (result.senders.length === 0) {
|
|
57
34
|
return ok(
|
|
58
35
|
JSON.stringify({
|
|
59
|
-
senders,
|
|
36
|
+
senders: [],
|
|
60
37
|
total_scanned: result.totalScanned,
|
|
61
38
|
query_used: result.queryUsed,
|
|
62
39
|
...(result.truncated ? { truncated: true } : {}),
|
|
63
|
-
|
|
40
|
+
message:
|
|
41
|
+
"No emails found matching the query. Try broadening the search (e.g. remove category filter or extend date range).",
|
|
64
42
|
}),
|
|
65
43
|
);
|
|
66
|
-
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Map to snake_case output format for LLM consumption
|
|
47
|
+
const senders = result.senders.map((s) => ({
|
|
48
|
+
id: s.id,
|
|
49
|
+
display_name: s.displayName,
|
|
50
|
+
email: s.email,
|
|
51
|
+
message_count: s.messageCount,
|
|
52
|
+
has_unsubscribe: s.hasUnsubscribe,
|
|
53
|
+
newest_message_id: s.newestMessageId,
|
|
54
|
+
search_query: s.searchQuery,
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
return ok(
|
|
58
|
+
JSON.stringify({
|
|
59
|
+
senders,
|
|
60
|
+
total_scanned: result.totalScanned,
|
|
61
|
+
query_used: result.queryUsed,
|
|
62
|
+
...(result.truncated ? { truncated: true } : {}),
|
|
63
|
+
note: `message_count reflects emails found per sender within the ${result.totalScanned} messages scanned. Use messaging_archive_by_sender with the sender's search_query to archive their messages.`,
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
67
66
|
} catch (e) {
|
|
68
67
|
return err(e instanceof Error ? e.message : String(e));
|
|
69
68
|
}
|
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
getMessagingProvider,
|
|
9
9
|
isPlatformEnabled,
|
|
10
10
|
} from "../../../../messaging/registry.js";
|
|
11
|
-
import {
|
|
11
|
+
import type { OAuthConnection } from "../../../../oauth/connection.js";
|
|
12
|
+
import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
|
|
12
13
|
import type { ToolExecutionResult } from "../../../../tools/types.js";
|
|
13
14
|
|
|
14
15
|
export function ok(content: string): ToolExecutionResult {
|
|
@@ -126,16 +127,15 @@ export function resolveProvider(platformInput?: string): MessagingProvider {
|
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
130
|
+
* Resolve an OAuthConnection (or empty string for non-OAuth providers)
|
|
131
|
+
* for the given messaging provider.
|
|
132
|
+
*
|
|
133
|
+
* Non-OAuth providers (e.g. Telegram) use isConnected() and don't need
|
|
134
|
+
* tokens — they receive an empty string which the string overload handles.
|
|
132
135
|
*/
|
|
133
|
-
export
|
|
136
|
+
export function getProviderConnection(
|
|
134
137
|
provider: MessagingProvider,
|
|
135
|
-
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
return fn("");
|
|
139
|
-
}
|
|
140
|
-
return withValidToken(provider.credentialService, fn);
|
|
138
|
+
): OAuthConnection | string {
|
|
139
|
+
if (provider.isConnected?.()) return "";
|
|
140
|
+
return resolveOAuthConnection(provider.credentialService);
|
|
141
141
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Shared utilities for slack skill tools.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import type { OAuthConnection } from "../../../../oauth/connection.js";
|
|
6
|
+
import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
|
|
7
7
|
import type { ToolExecutionResult } from "../../../../tools/types.js";
|
|
8
8
|
|
|
9
9
|
export function ok(content: string): ToolExecutionResult {
|
|
@@ -14,12 +14,6 @@ export function err(message: string): ToolExecutionResult {
|
|
|
14
14
|
return { content: message, isError: true };
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*/
|
|
20
|
-
export async function withSlackToken<T>(
|
|
21
|
-
fn: (token: string) => Promise<T>,
|
|
22
|
-
): Promise<T> {
|
|
23
|
-
const provider = getMessagingProvider("slack");
|
|
24
|
-
return withValidToken(provider.credentialService, fn);
|
|
17
|
+
export function getSlackConnection(): OAuthConnection {
|
|
18
|
+
return resolveOAuthConnection("integration:slack");
|
|
25
19
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
ToolContext,
|
|
4
4
|
ToolExecutionResult,
|
|
5
5
|
} from "../../../../tools/types.js";
|
|
6
|
-
import { err,
|
|
6
|
+
import { err, getSlackConnection, ok } from "./shared.js";
|
|
7
7
|
|
|
8
8
|
export async function run(
|
|
9
9
|
input: Record<string, unknown>,
|
|
@@ -18,10 +18,9 @@ export async function run(
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
21
|
+
const connection = getSlackConnection();
|
|
22
|
+
await addReaction(connection, channel, timestamp, emoji);
|
|
23
|
+
return ok(`Added :${emoji}: reaction.`);
|
|
25
24
|
} catch (e) {
|
|
26
25
|
return err(e instanceof Error ? e.message : String(e));
|
|
27
26
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
ToolContext,
|
|
4
4
|
ToolExecutionResult,
|
|
5
5
|
} from "../../../../tools/types.js";
|
|
6
|
-
import { err,
|
|
6
|
+
import { err, getSlackConnection, ok } from "./shared.js";
|
|
7
7
|
|
|
8
8
|
export async function run(
|
|
9
9
|
input: Record<string, unknown>,
|
|
@@ -16,23 +16,22 @@ export async function run(
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
try {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const connection = getSlackConnection();
|
|
20
|
+
const resp = await slack.conversationInfo(connection, channelId);
|
|
21
|
+
const conv = resp.channel;
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
const result = {
|
|
24
|
+
channelId: conv.id,
|
|
25
|
+
name: conv.name ?? conv.id,
|
|
26
|
+
topic: conv.topic?.value || null,
|
|
27
|
+
purpose: conv.purpose?.value || null,
|
|
28
|
+
isPrivate: conv.is_private ?? conv.is_group ?? false,
|
|
29
|
+
isArchived: conv.is_archived ?? false,
|
|
30
|
+
memberCount: conv.num_members ?? null,
|
|
31
|
+
latestActivityTs: conv.latest?.ts ?? null,
|
|
32
|
+
};
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
});
|
|
34
|
+
return ok(JSON.stringify(result, null, 2));
|
|
36
35
|
} catch (e) {
|
|
37
36
|
return err(e instanceof Error ? e.message : String(e));
|
|
38
37
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
ToolContext,
|
|
4
4
|
ToolExecutionResult,
|
|
5
5
|
} from "../../../../tools/types.js";
|
|
6
|
-
import { err,
|
|
6
|
+
import { err, getSlackConnection, ok } from "./shared.js";
|
|
7
7
|
|
|
8
8
|
export async function run(
|
|
9
9
|
input: Record<string, unknown>,
|
|
@@ -17,10 +17,9 @@ export async function run(
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
try {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
});
|
|
20
|
+
const connection = getSlackConnection();
|
|
21
|
+
await deleteMessage(connection, channel, timestamp);
|
|
22
|
+
return ok(`Message deleted.`);
|
|
24
23
|
} catch (e) {
|
|
25
24
|
return err(e instanceof Error ? e.message : String(e));
|
|
26
25
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
ToolContext,
|
|
4
4
|
ToolExecutionResult,
|
|
5
5
|
} from "../../../../tools/types.js";
|
|
6
|
-
import { err,
|
|
6
|
+
import { err, getSlackConnection, ok } from "./shared.js";
|
|
7
7
|
|
|
8
8
|
export async function run(
|
|
9
9
|
input: Record<string, unknown>,
|
|
@@ -18,10 +18,9 @@ export async function run(
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
21
|
+
const connection = getSlackConnection();
|
|
22
|
+
await updateMessage(connection, channel, timestamp, text);
|
|
23
|
+
return ok(`Message updated.`);
|
|
25
24
|
} catch (e) {
|
|
26
25
|
return err(e instanceof Error ? e.message : String(e));
|
|
27
26
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
ToolContext,
|
|
4
4
|
ToolExecutionResult,
|
|
5
5
|
} from "../../../../tools/types.js";
|
|
6
|
-
import { err,
|
|
6
|
+
import { err, getSlackConnection, ok } from "./shared.js";
|
|
7
7
|
|
|
8
8
|
export async function run(
|
|
9
9
|
input: Record<string, unknown>,
|
|
@@ -16,10 +16,9 @@ export async function run(
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
try {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
19
|
+
const connection = getSlackConnection();
|
|
20
|
+
await leaveConversation(connection, channel);
|
|
21
|
+
return ok("Left channel.");
|
|
23
22
|
} catch (e) {
|
|
24
23
|
return err(e instanceof Error ? e.message : String(e));
|
|
25
24
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { getConfig } from "../../../../config/loader.js";
|
|
2
2
|
import * as slack from "../../../../messaging/providers/slack/client.js";
|
|
3
3
|
import type { SlackConversation } from "../../../../messaging/providers/slack/types.js";
|
|
4
|
+
import type { OAuthConnection } from "../../../../oauth/connection.js";
|
|
4
5
|
import type {
|
|
5
6
|
ToolContext,
|
|
6
7
|
ToolExecutionResult,
|
|
7
8
|
} from "../../../../tools/types.js";
|
|
8
|
-
import { err,
|
|
9
|
+
import { err, getSlackConnection, ok } from "./shared.js";
|
|
9
10
|
|
|
10
11
|
interface ThreadSummary {
|
|
11
12
|
threadTs: string;
|
|
@@ -26,13 +27,16 @@ interface ChannelDigest {
|
|
|
26
27
|
|
|
27
28
|
const userNameCache = new Map<string, string>();
|
|
28
29
|
|
|
29
|
-
async function resolveUserName(
|
|
30
|
+
async function resolveUserName(
|
|
31
|
+
connection: OAuthConnection,
|
|
32
|
+
userId: string,
|
|
33
|
+
): Promise<string> {
|
|
30
34
|
if (!userId) return "unknown";
|
|
31
35
|
const cached = userNameCache.get(userId);
|
|
32
36
|
if (cached) return cached;
|
|
33
37
|
|
|
34
38
|
try {
|
|
35
|
-
const resp = await slack.userInfo(
|
|
39
|
+
const resp = await slack.userInfo(connection, userId);
|
|
36
40
|
const name =
|
|
37
41
|
resp.user.profile?.display_name ||
|
|
38
42
|
resp.user.profile?.real_name ||
|
|
@@ -46,7 +50,7 @@ async function resolveUserName(token: string, userId: string): Promise<string> {
|
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
async function scanChannel(
|
|
49
|
-
|
|
53
|
+
connection: OAuthConnection,
|
|
50
54
|
conv: SlackConversation,
|
|
51
55
|
oldestTs: string,
|
|
52
56
|
includeThreads: boolean,
|
|
@@ -57,7 +61,7 @@ async function scanChannel(
|
|
|
57
61
|
|
|
58
62
|
try {
|
|
59
63
|
const history = await slack.conversationHistory(
|
|
60
|
-
|
|
64
|
+
connection,
|
|
61
65
|
channelId,
|
|
62
66
|
100,
|
|
63
67
|
undefined,
|
|
@@ -71,7 +75,7 @@ async function scanChannel(
|
|
|
71
75
|
}
|
|
72
76
|
|
|
73
77
|
const keyParticipants = await Promise.all(
|
|
74
|
-
[...participantIds].map((uid) => resolveUserName(
|
|
78
|
+
[...participantIds].map((uid) => resolveUserName(connection, uid)),
|
|
75
79
|
);
|
|
76
80
|
|
|
77
81
|
const threadMessages = messages
|
|
@@ -86,7 +90,7 @@ async function scanChannel(
|
|
|
86
90
|
if (includeThreads) {
|
|
87
91
|
try {
|
|
88
92
|
const replies = await slack.conversationReplies(
|
|
89
|
-
|
|
93
|
+
connection,
|
|
90
94
|
channelId,
|
|
91
95
|
msg.ts,
|
|
92
96
|
10,
|
|
@@ -97,11 +101,11 @@ async function scanChannel(
|
|
|
97
101
|
}
|
|
98
102
|
participants = await Promise.all(
|
|
99
103
|
[...threadParticipantIds].map((uid) =>
|
|
100
|
-
resolveUserName(
|
|
104
|
+
resolveUserName(connection, uid),
|
|
101
105
|
),
|
|
102
106
|
);
|
|
103
107
|
} catch {
|
|
104
|
-
participants = [await resolveUserName(
|
|
108
|
+
participants = [await resolveUserName(connection, msg.user ?? "")];
|
|
105
109
|
}
|
|
106
110
|
}
|
|
107
111
|
|
|
@@ -260,15 +264,34 @@ export async function run(
|
|
|
260
264
|
const format = (input.format as string) ?? "text";
|
|
261
265
|
|
|
262
266
|
try {
|
|
263
|
-
|
|
264
|
-
|
|
267
|
+
const connection = getSlackConnection();
|
|
268
|
+
const oldestTs = String((Date.now() - hoursBack * 60 * 60 * 1000) / 1000);
|
|
265
269
|
|
|
266
|
-
|
|
267
|
-
|
|
270
|
+
let channelsToScan: SlackConversation[];
|
|
271
|
+
let failedLookups = 0;
|
|
268
272
|
|
|
269
|
-
|
|
273
|
+
if (channelIds?.length) {
|
|
274
|
+
const results = await Promise.allSettled(
|
|
275
|
+
channelIds.map((id) => slack.conversationInfo(connection, id)),
|
|
276
|
+
);
|
|
277
|
+
channelsToScan = results
|
|
278
|
+
.filter(
|
|
279
|
+
(
|
|
280
|
+
r,
|
|
281
|
+
): r is PromiseFulfilledResult<
|
|
282
|
+
Awaited<ReturnType<typeof slack.conversationInfo>>
|
|
283
|
+
> => r.status === "fulfilled",
|
|
284
|
+
)
|
|
285
|
+
.map((r) => r.value.channel);
|
|
286
|
+
failedLookups = results.filter((r) => r.status === "rejected").length;
|
|
287
|
+
} else {
|
|
288
|
+
const config = getConfig();
|
|
289
|
+
const preferredIds = config.skills?.entries?.slack?.config
|
|
290
|
+
?.preferredChannels as string[] | undefined;
|
|
291
|
+
|
|
292
|
+
if (preferredIds?.length) {
|
|
270
293
|
const results = await Promise.allSettled(
|
|
271
|
-
|
|
294
|
+
preferredIds.map((id) => slack.conversationInfo(connection, id)),
|
|
272
295
|
);
|
|
273
296
|
channelsToScan = results
|
|
274
297
|
.filter(
|
|
@@ -281,89 +304,69 @@ export async function run(
|
|
|
281
304
|
.map((r) => r.value.channel);
|
|
282
305
|
failedLookups = results.filter((r) => r.status === "rejected").length;
|
|
283
306
|
} else {
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
307
|
+
const allChannels: SlackConversation[] = [];
|
|
308
|
+
let cursor: string | undefined;
|
|
309
|
+
do {
|
|
310
|
+
const resp = await slack.listConversations(
|
|
311
|
+
connection,
|
|
312
|
+
"public_channel,private_channel",
|
|
313
|
+
true,
|
|
314
|
+
200,
|
|
315
|
+
cursor,
|
|
291
316
|
);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
)
|
|
300
|
-
.
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
let cursor: string | undefined;
|
|
305
|
-
do {
|
|
306
|
-
const resp = await slack.listConversations(
|
|
307
|
-
token,
|
|
308
|
-
"public_channel,private_channel",
|
|
309
|
-
true,
|
|
310
|
-
200,
|
|
311
|
-
cursor,
|
|
312
|
-
);
|
|
313
|
-
allChannels.push(...resp.channels);
|
|
314
|
-
cursor = resp.response_metadata?.next_cursor || undefined;
|
|
315
|
-
} while (cursor);
|
|
316
|
-
|
|
317
|
-
channelsToScan = allChannels
|
|
318
|
-
.filter((c) => c.is_member)
|
|
319
|
-
.sort((a, b) => {
|
|
320
|
-
const aTs = a.latest?.ts ? parseFloat(a.latest.ts) : 0;
|
|
321
|
-
const bTs = b.latest?.ts ? parseFloat(b.latest.ts) : 0;
|
|
322
|
-
return bTs - aTs;
|
|
323
|
-
})
|
|
324
|
-
.slice(0, maxChannels);
|
|
325
|
-
}
|
|
317
|
+
allChannels.push(...resp.channels);
|
|
318
|
+
cursor = resp.response_metadata?.next_cursor || undefined;
|
|
319
|
+
} while (cursor);
|
|
320
|
+
|
|
321
|
+
channelsToScan = allChannels
|
|
322
|
+
.filter((c) => c.is_member)
|
|
323
|
+
.sort((a, b) => {
|
|
324
|
+
const aTs = a.latest?.ts ? parseFloat(a.latest.ts) : 0;
|
|
325
|
+
const bTs = b.latest?.ts ? parseFloat(b.latest.ts) : 0;
|
|
326
|
+
return bTs - aTs;
|
|
327
|
+
})
|
|
328
|
+
.slice(0, maxChannels);
|
|
326
329
|
}
|
|
330
|
+
}
|
|
327
331
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const digests: ChannelDigest[] = scanResults
|
|
335
|
-
.filter(
|
|
336
|
-
(r): r is PromiseFulfilledResult<ChannelDigest> =>
|
|
337
|
-
r.status === "fulfilled",
|
|
338
|
-
)
|
|
339
|
-
.map((r) => r.value)
|
|
340
|
-
.filter((d) => d.messageCount > 0 || d.error);
|
|
341
|
-
|
|
342
|
-
const skippedCount = scanResults.filter(
|
|
343
|
-
(r) => r.status === "rejected",
|
|
344
|
-
).length;
|
|
345
|
-
|
|
346
|
-
if (format === "blocks") {
|
|
347
|
-
const blocks = buildBlockKitOutput(
|
|
348
|
-
digests,
|
|
349
|
-
hoursBack,
|
|
350
|
-
channelsToScan.length,
|
|
351
|
-
skippedCount,
|
|
352
|
-
);
|
|
353
|
-
return ok(JSON.stringify({ blocks }, null, 2));
|
|
354
|
-
}
|
|
332
|
+
const scanResults = await Promise.allSettled(
|
|
333
|
+
channelsToScan.map((conv) =>
|
|
334
|
+
scanChannel(connection, conv, oldestTs, includeThreads),
|
|
335
|
+
),
|
|
336
|
+
);
|
|
355
337
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
338
|
+
const digests: ChannelDigest[] = scanResults
|
|
339
|
+
.filter(
|
|
340
|
+
(r): r is PromiseFulfilledResult<ChannelDigest> =>
|
|
341
|
+
r.status === "fulfilled",
|
|
342
|
+
)
|
|
343
|
+
.map((r) => r.value)
|
|
344
|
+
.filter((d) => d.messageCount > 0 || d.error);
|
|
345
|
+
|
|
346
|
+
const skippedCount = scanResults.filter(
|
|
347
|
+
(r) => r.status === "rejected",
|
|
348
|
+
).length;
|
|
349
|
+
|
|
350
|
+
if (format === "blocks") {
|
|
351
|
+
const blocks = buildBlockKitOutput(
|
|
352
|
+
digests,
|
|
361
353
|
hoursBack,
|
|
362
|
-
|
|
363
|
-
|
|
354
|
+
channelsToScan.length,
|
|
355
|
+
skippedCount,
|
|
356
|
+
);
|
|
357
|
+
return ok(JSON.stringify({ blocks }, null, 2));
|
|
358
|
+
}
|
|
364
359
|
|
|
365
|
-
|
|
366
|
-
|
|
360
|
+
const result = {
|
|
361
|
+
scannedChannels: digests.length,
|
|
362
|
+
totalChannelsAttempted: channelsToScan.length,
|
|
363
|
+
skippedDueToErrors: skippedCount,
|
|
364
|
+
failedLookups,
|
|
365
|
+
hoursBack,
|
|
366
|
+
channels: digests,
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
return ok(JSON.stringify(result, null, 2));
|
|
367
370
|
} catch (e) {
|
|
368
371
|
return err(e instanceof Error ? e.message : String(e));
|
|
369
372
|
}
|
package/src/config/loader.ts
CHANGED
|
@@ -333,6 +333,12 @@ export function loadConfig(): AssistantConfig {
|
|
|
333
333
|
}
|
|
334
334
|
|
|
335
335
|
// Environment variables override everything
|
|
336
|
+
if (process.env.VELLUM_CONFIG_SANDBOX_ENABLED === "false") {
|
|
337
|
+
config.sandbox.enabled = false;
|
|
338
|
+
} else if (process.env.VELLUM_CONFIG_SANDBOX_ENABLED === "true") {
|
|
339
|
+
config.sandbox.enabled = true;
|
|
340
|
+
}
|
|
341
|
+
|
|
336
342
|
if (process.env.ANTHROPIC_API_KEY) {
|
|
337
343
|
config.apiKeys.anthropic = process.env.ANTHROPIC_API_KEY;
|
|
338
344
|
}
|
|
@@ -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
|
]);
|