@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
|
@@ -27,13 +27,8 @@ class HostFileWriteTool implements Tool {
|
|
|
27
27
|
type: "string",
|
|
28
28
|
description: "The content to write to the file",
|
|
29
29
|
},
|
|
30
|
-
reason: {
|
|
31
|
-
type: "string",
|
|
32
|
-
description:
|
|
33
|
-
"Brief non-technical explanation of why this file is being written, shown to the user as a status update. Use simple language a non-technical person would understand.",
|
|
34
|
-
},
|
|
35
30
|
},
|
|
36
|
-
required: ["path", "content"
|
|
31
|
+
required: ["path", "content"],
|
|
37
32
|
},
|
|
38
33
|
};
|
|
39
34
|
}
|
|
@@ -2,6 +2,7 @@ import type { McpServerConfig } from "../../config/schemas/mcp.js";
|
|
|
2
2
|
import type { McpServerManager } from "../../mcp/manager.js";
|
|
3
3
|
import { RiskLevel } from "../../permissions/types.js";
|
|
4
4
|
import type { ToolDefinition } from "../../providers/types.js";
|
|
5
|
+
import { schemaDefinesProperty } from "../schema-transforms.js";
|
|
5
6
|
import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
6
7
|
|
|
7
8
|
const riskMap: Record<string, RiskLevel> = {
|
|
@@ -36,6 +37,10 @@ export function createMcpTool(
|
|
|
36
37
|
): Tool {
|
|
37
38
|
const namespacedName = mcpToolName(serverId, metadata.name);
|
|
38
39
|
const riskLevel = riskMap[serverConfig.defaultRiskLevel] ?? RiskLevel.High;
|
|
40
|
+
const serverDefinesReason = schemaDefinesProperty(
|
|
41
|
+
metadata.inputSchema,
|
|
42
|
+
"reason",
|
|
43
|
+
);
|
|
39
44
|
|
|
40
45
|
return {
|
|
41
46
|
name: namespacedName,
|
|
@@ -59,7 +64,19 @@ export function createMcpTool(
|
|
|
59
64
|
_context: ToolContext,
|
|
60
65
|
): Promise<ToolExecutionResult> {
|
|
61
66
|
try {
|
|
62
|
-
|
|
67
|
+
// Strip injected reason before sending to MCP server
|
|
68
|
+
const { reason: _reason, ...mcpInput } = input as Record<
|
|
69
|
+
string,
|
|
70
|
+
unknown
|
|
71
|
+
> & {
|
|
72
|
+
reason?: unknown;
|
|
73
|
+
};
|
|
74
|
+
const forwardInput = serverDefinesReason ? input : mcpInput;
|
|
75
|
+
const result = await manager.callTool(
|
|
76
|
+
serverId,
|
|
77
|
+
metadata.name,
|
|
78
|
+
forwardInput,
|
|
79
|
+
);
|
|
63
80
|
return {
|
|
64
81
|
content: result.content,
|
|
65
82
|
isError: result.isError,
|
|
@@ -62,11 +62,6 @@ const memoryManageProperties = {
|
|
|
62
62
|
type: "string" as const,
|
|
63
63
|
description: "Short subject/topic label, 2-8 words (optional, save only)",
|
|
64
64
|
},
|
|
65
|
-
reason: {
|
|
66
|
-
type: "string" as const,
|
|
67
|
-
description:
|
|
68
|
-
"Brief non-technical explanation shown to the user as a status update",
|
|
69
|
-
},
|
|
70
65
|
};
|
|
71
66
|
|
|
72
67
|
export const memoryManageDefinition: ToolDefinition = {
|
|
@@ -863,11 +863,6 @@ class WebFetchTool implements Tool {
|
|
|
863
863
|
description:
|
|
864
864
|
"If true, allows requests to localhost/private-network hosts. Disabled by default for SSRF safety.",
|
|
865
865
|
},
|
|
866
|
-
reason: {
|
|
867
|
-
type: "string",
|
|
868
|
-
description:
|
|
869
|
-
"Brief non-technical explanation of what you are fetching and why, shown to the user as a status update. Use simple language a non-technical person would understand.",
|
|
870
|
-
},
|
|
871
866
|
},
|
|
872
867
|
required: ["url"],
|
|
873
868
|
},
|
|
@@ -302,11 +302,6 @@ class WebSearchTool implements Tool {
|
|
|
302
302
|
description:
|
|
303
303
|
'Filter by recency: "pd" (past day), "pw" (past week), "pm" (past month), "py" (past year). Only used with Brave provider.',
|
|
304
304
|
},
|
|
305
|
-
reason: {
|
|
306
|
-
type: "string",
|
|
307
|
-
description:
|
|
308
|
-
"Brief non-technical explanation of what you are searching for and why, shown to the user as a status update. Use simple language a non-technical person would understand.",
|
|
309
|
-
},
|
|
310
305
|
},
|
|
311
306
|
required: ["query"],
|
|
312
307
|
},
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { ToolDefinition } from "../providers/types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tools that should never have a `reason` field injected into their schema.
|
|
5
|
+
*/
|
|
6
|
+
export const REASON_SKIP_SET = new Set<string>([
|
|
7
|
+
"skill_execute",
|
|
8
|
+
"bash",
|
|
9
|
+
"host_bash",
|
|
10
|
+
"request_system_permission",
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Injects a `reason` string property into each tool definition's input schema,
|
|
15
|
+
* unless the tool is in the skip set, already has a reason field, or has a
|
|
16
|
+
* non-object schema.
|
|
17
|
+
*
|
|
18
|
+
* CRITICAL: Never mutates the input definitions — always returns deep clones
|
|
19
|
+
* for any modified definition, since `getDefinition()` returns shared refs.
|
|
20
|
+
*/
|
|
21
|
+
export function injectReasonField(
|
|
22
|
+
definitions: ToolDefinition[],
|
|
23
|
+
skip: Set<string> = REASON_SKIP_SET,
|
|
24
|
+
): ToolDefinition[] {
|
|
25
|
+
return definitions.map((def) => {
|
|
26
|
+
if (skip.has(def.name)) {
|
|
27
|
+
return def;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const schema = def.input_schema as Record<string, unknown>;
|
|
31
|
+
if (schema.type !== "object" || !schema.properties) {
|
|
32
|
+
return def;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const properties = schema.properties as Record<string, unknown>;
|
|
36
|
+
if (schemaDefinesProperty(schema, "reason")) {
|
|
37
|
+
return def;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Deep clone to avoid mutating shared refs
|
|
41
|
+
const newProperties = { ...properties, reason: { type: "string" } };
|
|
42
|
+
const existingRequired = Array.isArray(schema.required)
|
|
43
|
+
? [...schema.required, "reason"]
|
|
44
|
+
: ["reason"];
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
...def,
|
|
48
|
+
input_schema: {
|
|
49
|
+
...schema,
|
|
50
|
+
properties: newProperties,
|
|
51
|
+
required: existingRequired,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Checks whether a JSON Schema defines a given property name.
|
|
59
|
+
* Walks `allOf`, `oneOf`, `anyOf` recursively.
|
|
60
|
+
* Fail-closed on `$ref`: returns false if a `$ref` is encountered.
|
|
61
|
+
*/
|
|
62
|
+
export function schemaDefinesProperty(
|
|
63
|
+
schema: unknown,
|
|
64
|
+
propertyName: string,
|
|
65
|
+
): boolean {
|
|
66
|
+
if (schema == null || typeof schema !== "object") {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const s = schema as Record<string, unknown>;
|
|
71
|
+
|
|
72
|
+
// Fail-closed on $ref — we can't resolve it, so treat as "doesn't define it"
|
|
73
|
+
if ("$ref" in s) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Check direct properties
|
|
78
|
+
if (
|
|
79
|
+
s.properties &&
|
|
80
|
+
typeof s.properties === "object" &&
|
|
81
|
+
propertyName in (s.properties as Record<string, unknown>)
|
|
82
|
+
) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Walk composite keywords
|
|
87
|
+
for (const keyword of ["allOf", "oneOf", "anyOf"] as const) {
|
|
88
|
+
const arr = s[keyword];
|
|
89
|
+
if (Array.isArray(arr)) {
|
|
90
|
+
for (const member of arr) {
|
|
91
|
+
if (schemaDefinesProperty(member, propertyName)) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return false;
|
|
99
|
+
}
|
package/src/tools/skills/load.ts
CHANGED
|
@@ -119,11 +119,6 @@ export class SkillLoadTool implements Tool {
|
|
|
119
119
|
type: "string",
|
|
120
120
|
description: "The skill id or skill name to load.",
|
|
121
121
|
},
|
|
122
|
-
reason: {
|
|
123
|
-
type: "string",
|
|
124
|
-
description:
|
|
125
|
-
"Brief non-technical explanation of what you are loading and why, shown to the user as a status update. Use simple language a non-technical person would understand.",
|
|
126
|
-
},
|
|
127
122
|
},
|
|
128
123
|
required: ["skill"],
|
|
129
124
|
},
|
|
@@ -44,11 +44,6 @@ export const swarmDelegateTool: Tool = {
|
|
|
44
44
|
description:
|
|
45
45
|
"Maximum concurrent workers (1-6, default from config)",
|
|
46
46
|
},
|
|
47
|
-
reason: {
|
|
48
|
-
type: "string",
|
|
49
|
-
description:
|
|
50
|
-
"Brief non-technical explanation of what you are doing and why, shown to the user as a status update. Use simple language a non-technical person would understand.",
|
|
51
|
-
},
|
|
52
47
|
},
|
|
53
48
|
required: ["objective"],
|
|
54
49
|
},
|
|
@@ -2,8 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { ManagedAvatarError } from "../../media/avatar-types.js";
|
|
5
|
+
import { generateAvatar } from "../../media/avatar-router.js";
|
|
7
6
|
import { mapGeminiError } from "../../media/gemini-image-service.js";
|
|
8
7
|
import { RiskLevel } from "../../permissions/types.js";
|
|
9
8
|
import type { ToolDefinition } from "../../providers/types.js";
|
|
@@ -41,11 +40,6 @@ export const setAvatarTool: Tool = {
|
|
|
41
40
|
"A text description of the desired avatar appearance, " +
|
|
42
41
|
'e.g. "a friendly purple cat with green eyes wearing a tiny hat".',
|
|
43
42
|
},
|
|
44
|
-
reason: {
|
|
45
|
-
type: "string",
|
|
46
|
-
description:
|
|
47
|
-
"Brief non-technical explanation of what you are creating and why, shown to the user as a status update. Use simple language a non-technical person would understand.",
|
|
48
|
-
},
|
|
49
43
|
},
|
|
50
44
|
required: ["description"],
|
|
51
45
|
},
|
|
@@ -75,7 +69,7 @@ export const setAvatarTool: Tool = {
|
|
|
75
69
|
"Circular or rounded composition filling the canvas. " +
|
|
76
70
|
"Subtle background color (not white or transparent).";
|
|
77
71
|
|
|
78
|
-
const result = await
|
|
72
|
+
const result = await generateAvatar(prompt);
|
|
79
73
|
if (!result.imageBase64) {
|
|
80
74
|
return {
|
|
81
75
|
content: "Error: No image data returned. Please try again.",
|
|
@@ -92,14 +86,7 @@ export const setAvatarTool: Tool = {
|
|
|
92
86
|
writeFileSync(tmpPath, pngBuffer);
|
|
93
87
|
renameSync(tmpPath, avatarPath);
|
|
94
88
|
|
|
95
|
-
log.info(
|
|
96
|
-
{
|
|
97
|
-
avatarPath,
|
|
98
|
-
pathUsed: result.pathUsed,
|
|
99
|
-
correlationId: result.correlationId,
|
|
100
|
-
},
|
|
101
|
-
"Avatar saved successfully",
|
|
102
|
-
);
|
|
89
|
+
log.info({ avatarPath }, "Avatar saved successfully");
|
|
103
90
|
|
|
104
91
|
// Side-effect hook in tool-side-effects.ts broadcasts avatar_updated to all clients.
|
|
105
92
|
|
|
@@ -108,34 +95,6 @@ export const setAvatarTool: Tool = {
|
|
|
108
95
|
isError: false,
|
|
109
96
|
};
|
|
110
97
|
} catch (error) {
|
|
111
|
-
if (error instanceof ManagedAvatarError) {
|
|
112
|
-
log.error(
|
|
113
|
-
{
|
|
114
|
-
error: error.message,
|
|
115
|
-
statusCode: error.statusCode,
|
|
116
|
-
code: error.code,
|
|
117
|
-
},
|
|
118
|
-
"Avatar generation failed (managed)",
|
|
119
|
-
);
|
|
120
|
-
if (error.statusCode === 429) {
|
|
121
|
-
return {
|
|
122
|
-
content:
|
|
123
|
-
"Avatar generation is currently rate limited. Please try again in a moment.",
|
|
124
|
-
isError: true,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
if (error.statusCode >= 500) {
|
|
128
|
-
return {
|
|
129
|
-
content:
|
|
130
|
-
"Avatar generation is temporarily unavailable. Please try again later.",
|
|
131
|
-
isError: true,
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
return {
|
|
135
|
-
content: `Avatar generation failed: ${error.message}`,
|
|
136
|
-
isError: true,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
98
|
const message = mapGeminiError(error);
|
|
140
99
|
log.error({ error: message }, "Avatar generation failed");
|
|
141
100
|
return {
|
|
@@ -126,11 +126,6 @@ export const uiShowTool: Tool = {
|
|
|
126
126
|
description:
|
|
127
127
|
"Whether to block until the user interacts with an action. Defaults to true when actions are provided.",
|
|
128
128
|
},
|
|
129
|
-
reason: {
|
|
130
|
-
type: "string",
|
|
131
|
-
description:
|
|
132
|
-
"Brief non-technical explanation of what you are showing and why, shown to the user as a status update. Use simple language a non-technical person would understand.",
|
|
133
|
-
},
|
|
134
129
|
},
|
|
135
130
|
required: ["surface_type", "data"],
|
|
136
131
|
},
|
|
@@ -168,11 +163,6 @@ export const uiUpdateTool: Tool = {
|
|
|
168
163
|
type: "object",
|
|
169
164
|
description: "Partial data to merge into the existing surface data",
|
|
170
165
|
},
|
|
171
|
-
reason: {
|
|
172
|
-
type: "string",
|
|
173
|
-
description:
|
|
174
|
-
"Brief non-technical explanation of what you are updating and why, shown to the user as a status update. Use simple language a non-technical person would understand.",
|
|
175
|
-
},
|
|
176
166
|
},
|
|
177
167
|
required: ["surface_id", "data"],
|
|
178
168
|
},
|
|
@@ -204,11 +194,6 @@ export const uiDismissTool: Tool = {
|
|
|
204
194
|
type: "string",
|
|
205
195
|
description: "The ID of the surface to dismiss",
|
|
206
196
|
},
|
|
207
|
-
reason: {
|
|
208
|
-
type: "string",
|
|
209
|
-
description:
|
|
210
|
-
"Brief non-technical explanation of what you are dismissing and why, shown to the user as a status update. Use simple language a non-technical person would understand.",
|
|
211
|
-
},
|
|
212
197
|
},
|
|
213
198
|
required: ["surface_id"],
|
|
214
199
|
},
|
|
@@ -42,11 +42,6 @@ class ScreenWatchTool implements Tool {
|
|
|
42
42
|
type: "string",
|
|
43
43
|
description: "What to focus on observing",
|
|
44
44
|
},
|
|
45
|
-
reason: {
|
|
46
|
-
type: "string",
|
|
47
|
-
description:
|
|
48
|
-
"Brief non-technical explanation of what you are watching and why, shown to the user as a status update. Use simple language a non-technical person would understand.",
|
|
49
|
-
},
|
|
50
45
|
},
|
|
51
46
|
required: ["focus_area"],
|
|
52
47
|
},
|
package/src/version.ts
CHANGED
|
@@ -32,3 +32,13 @@ function resolveVersion(): string {
|
|
|
32
32
|
// Falls back to "0.0.0-dev" for local development, or resolves the dev
|
|
33
33
|
// placeholder to package.json version when explicitly set in CI.
|
|
34
34
|
export const APP_VERSION: string = resolveVersion();
|
|
35
|
+
|
|
36
|
+
// Commit SHA is embedded at compile time via --define in CI.
|
|
37
|
+
// Falls back to "unknown" for local development.
|
|
38
|
+
function resolveCommitSha(): string {
|
|
39
|
+
const sha = process.env.COMMIT_SHA;
|
|
40
|
+
if (!sha || sha === "unknown") return "unknown";
|
|
41
|
+
return sha;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const COMMIT_SHA: string = resolveCommitSha();
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* `notifications` scope (classic) or Notification read permission (fine-grained).
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import type { OAuthConnection } from "../../oauth/connection.js";
|
|
14
|
+
import { resolveOAuthConnection } from "../../oauth/connection-resolver.js";
|
|
14
15
|
import { getLogger } from "../../util/logger.js";
|
|
15
16
|
import { truncate } from "../../util/truncate.js";
|
|
16
17
|
import type {
|
|
@@ -21,8 +22,6 @@ import type {
|
|
|
21
22
|
|
|
22
23
|
const log = getLogger("watcher:github");
|
|
23
24
|
|
|
24
|
-
const GITHUB_API_BASE = "https://api.github.com";
|
|
25
|
-
|
|
26
25
|
// ── API types ──────────────────────────────────────────────────────────────────
|
|
27
26
|
|
|
28
27
|
interface GitHubNotification {
|
|
@@ -82,31 +81,32 @@ function notificationToItem(n: GitHubNotification): WatcherItem {
|
|
|
82
81
|
|
|
83
82
|
/** Fetch a single page of notifications since a timestamp. */
|
|
84
83
|
async function fetchNotificationsPage(
|
|
85
|
-
|
|
84
|
+
connection: OAuthConnection,
|
|
86
85
|
since: string,
|
|
87
86
|
page: number,
|
|
88
87
|
): Promise<{ items: GitHubNotification[]; hasMore: boolean }> {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
const resp = await connection.request({
|
|
89
|
+
method: "GET",
|
|
90
|
+
path: "/notifications",
|
|
91
|
+
query: {
|
|
92
|
+
all: "false", // only unread
|
|
93
|
+
since,
|
|
94
|
+
per_page: "50",
|
|
95
|
+
page: String(page),
|
|
96
|
+
},
|
|
97
97
|
headers: {
|
|
98
|
-
Authorization: `Bearer ${token}`,
|
|
99
98
|
Accept: "application/vnd.github+json",
|
|
100
99
|
"X-GitHub-Api-Version": "2022-11-28",
|
|
101
100
|
},
|
|
102
101
|
});
|
|
103
102
|
|
|
104
|
-
if (
|
|
105
|
-
const body =
|
|
103
|
+
if (resp.status >= 400) {
|
|
104
|
+
const body =
|
|
105
|
+
typeof resp.body === "string" ? resp.body : JSON.stringify(resp.body);
|
|
106
106
|
throw new Error(`GitHub Notifications API ${resp.status}: ${body}`);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
const items =
|
|
109
|
+
const items = resp.body as GitHubNotification[];
|
|
110
110
|
// GitHub returns 50 per page; if we got a full page there may be more
|
|
111
111
|
const hasMore = items.length === 50;
|
|
112
112
|
return { items, hasMore };
|
|
@@ -130,44 +130,43 @@ export const githubProvider: WatcherProvider = {
|
|
|
130
130
|
_config: Record<string, unknown>,
|
|
131
131
|
_watcherKey: string,
|
|
132
132
|
): Promise<FetchResult> {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (!hasMore) break;
|
|
159
|
-
page++;
|
|
133
|
+
const connection = resolveOAuthConnection(credentialService);
|
|
134
|
+
const since = watermark ?? new Date().toISOString();
|
|
135
|
+
const items: WatcherItem[] = [];
|
|
136
|
+
let page = 1;
|
|
137
|
+
|
|
138
|
+
while (true) {
|
|
139
|
+
const { items: pageItems, hasMore } = await fetchNotificationsPage(
|
|
140
|
+
connection,
|
|
141
|
+
since,
|
|
142
|
+
page,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
for (const n of pageItems) {
|
|
146
|
+
// Only surface notifications for reasons that warrant attention
|
|
147
|
+
const relevantReasons = new Set([
|
|
148
|
+
"assign",
|
|
149
|
+
"mention",
|
|
150
|
+
"review_requested",
|
|
151
|
+
"team_mention",
|
|
152
|
+
]);
|
|
153
|
+
if (!relevantReasons.has(n.reason)) continue;
|
|
154
|
+
|
|
155
|
+
items.push(notificationToItem(n));
|
|
160
156
|
}
|
|
161
157
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
158
|
+
if (!hasMore) break;
|
|
159
|
+
page++;
|
|
160
|
+
}
|
|
165
161
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
162
|
+
// New watermark: the time just before we fetched so we don't miss events
|
|
163
|
+
// that arrive between poll cycles.
|
|
164
|
+
const newWatermark = new Date().toISOString();
|
|
165
|
+
|
|
166
|
+
log.info(
|
|
167
|
+
{ count: items.length, watermark: newWatermark },
|
|
168
|
+
"GitHub: fetched new notifications",
|
|
169
|
+
);
|
|
170
|
+
return { items, watermark: newWatermark };
|
|
172
171
|
},
|
|
173
172
|
};
|