@vellumai/cli 0.11.10-dev.202609110043.1ff55a1 → 0.11.10-staging.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. package/node_modules/@vellumai/avatar-manifest/package.json +1 -2
  2. package/node_modules/@vellumai/local-mode/node_modules/@vellumai/avatar-manifest/package.json +1 -2
  3. package/node_modules/@vellumai/local-mode/node_modules/@vellumai/service-contracts/package.json +1 -2
  4. package/node_modules/@vellumai/local-mode/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -31
  5. package/node_modules/@vellumai/local-mode/node_modules/@vellumai/service-contracts/src/channels.ts +3 -28
  6. package/node_modules/@vellumai/local-mode/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
  7. package/node_modules/@vellumai/local-mode/node_modules/@vellumai/service-contracts/src/reactions.ts +5 -85
  8. package/node_modules/@vellumai/service-contracts/package.json +1 -2
  9. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -31
  10. package/node_modules/@vellumai/service-contracts/src/channels.ts +3 -28
  11. package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
  12. package/node_modules/@vellumai/service-contracts/src/reactions.ts +5 -85
  13. package/package.json +1 -1
  14. package/src/lib/provider-secrets.ts +1 -4
  15. package/node_modules/@vellumai/avatar-manifest/src/__tests__/notification-avatar.test.ts +0 -220
  16. package/node_modules/@vellumai/avatar-manifest/src/notification-avatar.ts +0 -139
  17. package/node_modules/@vellumai/local-mode/node_modules/@vellumai/avatar-manifest/src/__tests__/notification-avatar.test.ts +0 -220
  18. package/node_modules/@vellumai/local-mode/node_modules/@vellumai/avatar-manifest/src/notification-avatar.ts +0 -139
  19. package/node_modules/@vellumai/local-mode/node_modules/@vellumai/service-contracts/src/__tests__/plan-credit.test.ts +0 -51
  20. package/node_modules/@vellumai/local-mode/node_modules/@vellumai/service-contracts/src/plan-credit.ts +0 -66
  21. package/node_modules/@vellumai/service-contracts/src/__tests__/plan-credit.test.ts +0 -51
  22. package/node_modules/@vellumai/service-contracts/src/plan-credit.ts +0 -66
@@ -6,8 +6,7 @@
6
6
  "type": "module",
7
7
  "exports": {
8
8
  ".": "./src/index.ts",
9
- "./accent": "./src/accent.ts",
10
- "./notification-avatar": "./src/notification-avatar.ts"
9
+ "./accent": "./src/accent.ts"
11
10
  },
12
11
  "scripts": {
13
12
  "typecheck": "bunx tsc --noEmit",
@@ -6,8 +6,7 @@
6
6
  "type": "module",
7
7
  "exports": {
8
8
  ".": "./src/index.ts",
9
- "./accent": "./src/accent.ts",
10
- "./notification-avatar": "./src/notification-avatar.ts"
9
+ "./accent": "./src/accent.ts"
11
10
  },
12
11
  "scripts": {
13
12
  "typecheck": "bunx tsc --noEmit",
@@ -26,8 +26,7 @@
26
26
  "./error": "./src/error.ts",
27
27
  "./reactions": "./src/reactions.ts",
28
28
  "./guardian-requests": "./src/guardian-requests.ts",
29
- "./platform-credential": "./src/platform-credential.ts",
30
- "./plan-credit": "./src/plan-credit.ts"
29
+ "./platform-credential": "./src/platform-credential.ts"
31
30
  },
32
31
  "scripts": {
33
32
  "typecheck": "bunx tsc --noEmit",
@@ -1,10 +1,8 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import {
4
- botProviderForChannel,
5
4
  CHANNEL_BOT_PROVIDER,
6
5
  CHANNEL_IDS,
7
- channelForBotProvider,
8
6
  isChannelBotProvider,
9
7
  isChannelUserIntegration,
10
8
  isChannelId,
@@ -43,35 +41,6 @@ describe("isChannelId", () => {
43
41
  });
44
42
  });
45
43
 
46
- describe("botProviderForChannel and channelForBotProvider", () => {
47
- test("are inverses over every entry of the map", () => {
48
- for (const [channelId, botProviderKey] of Object.entries(
49
- CHANNEL_BOT_PROVIDER,
50
- )) {
51
- expect(botProviderForChannel(channelId)).toBe(botProviderKey);
52
- expect(channelForBotProvider(botProviderKey)).toBe(
53
- channelId as keyof typeof CHANNEL_BOT_PROVIDER,
54
- );
55
- }
56
- });
57
-
58
- test("answer nothing for a channel without a bot, a person's grant, or an unknown key", () => {
59
- expect(botProviderForChannel("phone")).toBeUndefined();
60
- expect(botProviderForChannel("vellum")).toBeUndefined();
61
- expect(botProviderForChannel("not-a-channel")).toBeUndefined();
62
- // `slack` is the person's integration standing beside the bot's key.
63
- expect(channelForBotProvider("slack")).toBeUndefined();
64
- expect(channelForBotProvider("google")).toBeUndefined();
65
- });
66
-
67
- test("never resolve an inherited object property as a channel or a key", () => {
68
- for (const name of ["constructor", "toString", "__proto__"]) {
69
- expect(botProviderForChannel(name)).toBeUndefined();
70
- expect(channelForBotProvider(name)).toBeUndefined();
71
- }
72
- });
73
- });
74
-
75
44
  describe("isChannelUserIntegration", () => {
76
45
  test("names the grant standing beside a bot of the same brand", () => {
77
46
  expect(isChannelUserIntegration("slack")).toBe(true);
@@ -93,34 +93,9 @@ export const CHANNEL_BOT_PROVIDER = {
93
93
  * connected" question, for any provider key.
94
94
  */
95
95
  export function isChannelBotProvider(providerKey: string): boolean {
96
- return channelForBotProvider(providerKey) !== undefined;
97
- }
98
-
99
- /**
100
- * The provider key holding a channel's bot credential, or `undefined` when
101
- * the channel has none, or is not a channel at all. Walks the map's own
102
- * entries, so an inherited object property name is never a channel.
103
- */
104
- export function botProviderForChannel(channelId: string): string | undefined {
105
- return Object.entries(CHANNEL_BOT_PROVIDER).find(
106
- ([id]) => id === channelId,
107
- )?.[1];
108
- }
109
-
110
- /**
111
- * The channel whose bot credential a provider key holds, or `undefined` when
112
- * the key is not a bot's. The inverse of `botProviderForChannel`, for a
113
- * surface that has only the provider key in hand and needs to speak in the
114
- * channel's vocabulary.
115
- */
116
- export function channelForBotProvider(
117
- providerKey: string,
118
- ): keyof typeof CHANNEL_BOT_PROVIDER | undefined {
119
- return (
120
- Object.entries(CHANNEL_BOT_PROVIDER) as Array<
121
- [keyof typeof CHANNEL_BOT_PROVIDER, string]
122
- >
123
- ).find(([, key]) => key === providerKey)?.[0];
96
+ return (Object.values(CHANNEL_BOT_PROVIDER) as readonly string[]).includes(
97
+ providerKey,
98
+ );
124
99
  }
125
100
 
126
101
  /**
@@ -28,7 +28,6 @@ export * from "./rpc.js";
28
28
  export * from "./trust-rules.js";
29
29
  export * from "./ingress.js";
30
30
  export * from "./no-response.js";
31
- export * from "./plan-credit.js";
32
31
  export * from "./platform-credential.js";
33
32
  export * from "./remote-web-pairing.js";
34
33
  export * from "./twilio-ingress.js";
@@ -7,13 +7,11 @@
7
7
  * is spelled. Modelled on Zulip's `reaction_type`, the one surveyed system
8
8
  * that separates the namespace from the name.
9
9
  *
10
- * `shortcode` is a name in a channel's own namespace that the channel's
11
- * adapter could not place among the standard emoji. Slack sends `+1` and
12
- * `blob_wave` alike, as names; its normalizer resolves the standard ones to
13
- * `unicode` from Slack's own list, and what remains is a workspace upload
14
- * only the workspace can render. It is a distinct kind from `unicode`, not
15
- * a stand-in for an unknown one, and nothing past an adapter needs a
16
- * channel's naming to read it.
10
+ * `shortcode` is a name in a channel's own namespace whose kind the channel
11
+ * does not disclose: Slack sends `+1` for the standard emoji and `blob_wave`
12
+ * for a workspace upload with nothing to tell them apart, and only the
13
+ * workspace token can resolve the second. It is a distinct kind from
14
+ * `unicode`, not a stand-in for an unknown one.
17
15
  */
18
16
  import { z } from "zod";
19
17
 
@@ -41,12 +39,6 @@ export const ReactionEmojiFieldsSchema = z.object({
41
39
  });
42
40
  export type ReactionEmojiFields = z.infer<typeof ReactionEmojiFieldsSchema>;
43
41
 
44
- /** The typed fields with the kind and name known. */
45
- export type ReactionEmojiIdentity = ReactionEmojiFields & {
46
- emojiKind: ReactionEmojiKind;
47
- emojiName: string;
48
- };
49
-
50
42
  /**
51
43
  * The typed emoji fields a source actually carries, with undefined ones
52
44
  * omitted: an absent key and a present-but-undefined one serialize alike, but the
@@ -66,75 +58,3 @@ export function pickReactionEmojiFields(
66
58
  : {}),
67
59
  };
68
60
  }
69
-
70
- /**
71
- * Parse Discord's custom-emoji mention form. The form travels the wire as a
72
- * reaction's spelling, so more than one package reads it: the daemon rebuilds
73
- * a REST path from it when the assistant reacts, and a row carrying only the
74
- * spelling recovers its kind from it. One parser, so the two cannot disagree
75
- * about what counts as one.
76
- *
77
- * `animated` reports whether the spelling carries the `a` marker. Discord's
78
- * normalizer never writes that marker, so it is read only from spellings that
79
- * arrive from elsewhere: a row written by another producer, or a value the
80
- * model hands back as it received it.
81
- */
82
- export function parseDiscordEmojiMention(
83
- emoji: string,
84
- ): { name: string; id: string; animated: boolean } | null {
85
- const match = /^<(a?):([^:>]+):(\d+)>$/.exec(emoji);
86
- return match
87
- ? { name: match[2]!, id: match[3]!, animated: match[1] === "a" }
88
- : null;
89
- }
90
-
91
- /**
92
- * Recover an emoji's kind from its spelling alone. This is the one inference
93
- * the design permits, reserved for a value that carries the string and no
94
- * typed fields: a persisted row or a replayed retry payload. A value that
95
- * declares its kind never reaches this; `reactionEmojiIdentity` makes that
96
- * choice for every reader.
97
- *
98
- * A mention form is unambiguous. Past that the two remaining kinds are told
99
- * apart by whether the string is a name at all: a channel's shortcode is
100
- * ASCII word characters, optionally carrying Slack's `::skin-tone-N`
101
- * suffix, and anything else is the character itself.
102
- */
103
- export function classifyReactionEmojiSpelling(
104
- emoji: string,
105
- ): ReactionEmojiIdentity {
106
- const custom = parseDiscordEmojiMention(emoji);
107
- if (custom) {
108
- // The plain `<:name:id>` form says nothing about animation: the
109
- // normalizer spells every custom emoji that way and reports animation
110
- // in the typed field instead, so a spelling without the `a` marker is
111
- // "unrecorded", not "not animated". Only the `<a:` form asserts it.
112
- return {
113
- emojiKind: "custom",
114
- emojiName: custom.name,
115
- emojiId: custom.id,
116
- ...(custom.animated ? { emojiAnimated: true } : {}),
117
- };
118
- }
119
- return /^[\w+-]+(::skin-tone-[2-6])?$/.test(emoji)
120
- ? { emojiKind: "shortcode", emojiName: emoji }
121
- : { emojiKind: "unicode", emojiName: emoji };
122
- }
123
-
124
- /**
125
- * The typed identity of a reaction's emoji: the fields it declares when it
126
- * declares a kind, otherwise the kind recovered from its spelling. Every
127
- * reader that must know what an emoji is goes through this, so the wire
128
- * contract and the web agree on when the spelling is consulted.
129
- */
130
- export function reactionEmojiIdentity(
131
- reaction: { emoji: string } & ReactionEmojiFields,
132
- ): ReactionEmojiIdentity {
133
- return reaction.emojiKind !== undefined && reaction.emojiName !== undefined
134
- ? {
135
- ...pickReactionEmojiFields(reaction),
136
- emojiKind: reaction.emojiKind,
137
- emojiName: reaction.emojiName,
138
- }
139
- : classifyReactionEmojiSpelling(reaction.emoji);
140
- }
@@ -26,8 +26,7 @@
26
26
  "./error": "./src/error.ts",
27
27
  "./reactions": "./src/reactions.ts",
28
28
  "./guardian-requests": "./src/guardian-requests.ts",
29
- "./platform-credential": "./src/platform-credential.ts",
30
- "./plan-credit": "./src/plan-credit.ts"
29
+ "./platform-credential": "./src/platform-credential.ts"
31
30
  },
32
31
  "scripts": {
33
32
  "typecheck": "bunx tsc --noEmit",
@@ -1,10 +1,8 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import {
4
- botProviderForChannel,
5
4
  CHANNEL_BOT_PROVIDER,
6
5
  CHANNEL_IDS,
7
- channelForBotProvider,
8
6
  isChannelBotProvider,
9
7
  isChannelUserIntegration,
10
8
  isChannelId,
@@ -43,35 +41,6 @@ describe("isChannelId", () => {
43
41
  });
44
42
  });
45
43
 
46
- describe("botProviderForChannel and channelForBotProvider", () => {
47
- test("are inverses over every entry of the map", () => {
48
- for (const [channelId, botProviderKey] of Object.entries(
49
- CHANNEL_BOT_PROVIDER,
50
- )) {
51
- expect(botProviderForChannel(channelId)).toBe(botProviderKey);
52
- expect(channelForBotProvider(botProviderKey)).toBe(
53
- channelId as keyof typeof CHANNEL_BOT_PROVIDER,
54
- );
55
- }
56
- });
57
-
58
- test("answer nothing for a channel without a bot, a person's grant, or an unknown key", () => {
59
- expect(botProviderForChannel("phone")).toBeUndefined();
60
- expect(botProviderForChannel("vellum")).toBeUndefined();
61
- expect(botProviderForChannel("not-a-channel")).toBeUndefined();
62
- // `slack` is the person's integration standing beside the bot's key.
63
- expect(channelForBotProvider("slack")).toBeUndefined();
64
- expect(channelForBotProvider("google")).toBeUndefined();
65
- });
66
-
67
- test("never resolve an inherited object property as a channel or a key", () => {
68
- for (const name of ["constructor", "toString", "__proto__"]) {
69
- expect(botProviderForChannel(name)).toBeUndefined();
70
- expect(channelForBotProvider(name)).toBeUndefined();
71
- }
72
- });
73
- });
74
-
75
44
  describe("isChannelUserIntegration", () => {
76
45
  test("names the grant standing beside a bot of the same brand", () => {
77
46
  expect(isChannelUserIntegration("slack")).toBe(true);
@@ -93,34 +93,9 @@ export const CHANNEL_BOT_PROVIDER = {
93
93
  * connected" question, for any provider key.
94
94
  */
95
95
  export function isChannelBotProvider(providerKey: string): boolean {
96
- return channelForBotProvider(providerKey) !== undefined;
97
- }
98
-
99
- /**
100
- * The provider key holding a channel's bot credential, or `undefined` when
101
- * the channel has none, or is not a channel at all. Walks the map's own
102
- * entries, so an inherited object property name is never a channel.
103
- */
104
- export function botProviderForChannel(channelId: string): string | undefined {
105
- return Object.entries(CHANNEL_BOT_PROVIDER).find(
106
- ([id]) => id === channelId,
107
- )?.[1];
108
- }
109
-
110
- /**
111
- * The channel whose bot credential a provider key holds, or `undefined` when
112
- * the key is not a bot's. The inverse of `botProviderForChannel`, for a
113
- * surface that has only the provider key in hand and needs to speak in the
114
- * channel's vocabulary.
115
- */
116
- export function channelForBotProvider(
117
- providerKey: string,
118
- ): keyof typeof CHANNEL_BOT_PROVIDER | undefined {
119
- return (
120
- Object.entries(CHANNEL_BOT_PROVIDER) as Array<
121
- [keyof typeof CHANNEL_BOT_PROVIDER, string]
122
- >
123
- ).find(([, key]) => key === providerKey)?.[0];
96
+ return (Object.values(CHANNEL_BOT_PROVIDER) as readonly string[]).includes(
97
+ providerKey,
98
+ );
124
99
  }
125
100
 
126
101
  /**
@@ -28,7 +28,6 @@ export * from "./rpc.js";
28
28
  export * from "./trust-rules.js";
29
29
  export * from "./ingress.js";
30
30
  export * from "./no-response.js";
31
- export * from "./plan-credit.js";
32
31
  export * from "./platform-credential.js";
33
32
  export * from "./remote-web-pairing.js";
34
33
  export * from "./twilio-ingress.js";
@@ -7,13 +7,11 @@
7
7
  * is spelled. Modelled on Zulip's `reaction_type`, the one surveyed system
8
8
  * that separates the namespace from the name.
9
9
  *
10
- * `shortcode` is a name in a channel's own namespace that the channel's
11
- * adapter could not place among the standard emoji. Slack sends `+1` and
12
- * `blob_wave` alike, as names; its normalizer resolves the standard ones to
13
- * `unicode` from Slack's own list, and what remains is a workspace upload
14
- * only the workspace can render. It is a distinct kind from `unicode`, not
15
- * a stand-in for an unknown one, and nothing past an adapter needs a
16
- * channel's naming to read it.
10
+ * `shortcode` is a name in a channel's own namespace whose kind the channel
11
+ * does not disclose: Slack sends `+1` for the standard emoji and `blob_wave`
12
+ * for a workspace upload with nothing to tell them apart, and only the
13
+ * workspace token can resolve the second. It is a distinct kind from
14
+ * `unicode`, not a stand-in for an unknown one.
17
15
  */
18
16
  import { z } from "zod";
19
17
 
@@ -41,12 +39,6 @@ export const ReactionEmojiFieldsSchema = z.object({
41
39
  });
42
40
  export type ReactionEmojiFields = z.infer<typeof ReactionEmojiFieldsSchema>;
43
41
 
44
- /** The typed fields with the kind and name known. */
45
- export type ReactionEmojiIdentity = ReactionEmojiFields & {
46
- emojiKind: ReactionEmojiKind;
47
- emojiName: string;
48
- };
49
-
50
42
  /**
51
43
  * The typed emoji fields a source actually carries, with undefined ones
52
44
  * omitted: an absent key and a present-but-undefined one serialize alike, but the
@@ -66,75 +58,3 @@ export function pickReactionEmojiFields(
66
58
  : {}),
67
59
  };
68
60
  }
69
-
70
- /**
71
- * Parse Discord's custom-emoji mention form. The form travels the wire as a
72
- * reaction's spelling, so more than one package reads it: the daemon rebuilds
73
- * a REST path from it when the assistant reacts, and a row carrying only the
74
- * spelling recovers its kind from it. One parser, so the two cannot disagree
75
- * about what counts as one.
76
- *
77
- * `animated` reports whether the spelling carries the `a` marker. Discord's
78
- * normalizer never writes that marker, so it is read only from spellings that
79
- * arrive from elsewhere: a row written by another producer, or a value the
80
- * model hands back as it received it.
81
- */
82
- export function parseDiscordEmojiMention(
83
- emoji: string,
84
- ): { name: string; id: string; animated: boolean } | null {
85
- const match = /^<(a?):([^:>]+):(\d+)>$/.exec(emoji);
86
- return match
87
- ? { name: match[2]!, id: match[3]!, animated: match[1] === "a" }
88
- : null;
89
- }
90
-
91
- /**
92
- * Recover an emoji's kind from its spelling alone. This is the one inference
93
- * the design permits, reserved for a value that carries the string and no
94
- * typed fields: a persisted row or a replayed retry payload. A value that
95
- * declares its kind never reaches this; `reactionEmojiIdentity` makes that
96
- * choice for every reader.
97
- *
98
- * A mention form is unambiguous. Past that the two remaining kinds are told
99
- * apart by whether the string is a name at all: a channel's shortcode is
100
- * ASCII word characters, optionally carrying Slack's `::skin-tone-N`
101
- * suffix, and anything else is the character itself.
102
- */
103
- export function classifyReactionEmojiSpelling(
104
- emoji: string,
105
- ): ReactionEmojiIdentity {
106
- const custom = parseDiscordEmojiMention(emoji);
107
- if (custom) {
108
- // The plain `<:name:id>` form says nothing about animation: the
109
- // normalizer spells every custom emoji that way and reports animation
110
- // in the typed field instead, so a spelling without the `a` marker is
111
- // "unrecorded", not "not animated". Only the `<a:` form asserts it.
112
- return {
113
- emojiKind: "custom",
114
- emojiName: custom.name,
115
- emojiId: custom.id,
116
- ...(custom.animated ? { emojiAnimated: true } : {}),
117
- };
118
- }
119
- return /^[\w+-]+(::skin-tone-[2-6])?$/.test(emoji)
120
- ? { emojiKind: "shortcode", emojiName: emoji }
121
- : { emojiKind: "unicode", emojiName: emoji };
122
- }
123
-
124
- /**
125
- * The typed identity of a reaction's emoji: the fields it declares when it
126
- * declares a kind, otherwise the kind recovered from its spelling. Every
127
- * reader that must know what an emoji is goes through this, so the wire
128
- * contract and the web agree on when the spelling is consulted.
129
- */
130
- export function reactionEmojiIdentity(
131
- reaction: { emoji: string } & ReactionEmojiFields,
132
- ): ReactionEmojiIdentity {
133
- return reaction.emojiKind !== undefined && reaction.emojiName !== undefined
134
- ? {
135
- ...pickReactionEmojiFields(reaction),
136
- emojiKind: reaction.emojiKind,
137
- emojiName: reaction.emojiName,
138
- }
139
- : classifyReactionEmojiSpelling(reaction.emoji);
140
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/cli",
3
- "version": "0.11.10-dev.202609110043.1ff55a1",
3
+ "version": "0.11.10-staging.1",
4
4
  "description": "CLI tools for vellum-assistant",
5
5
  "type": "module",
6
6
  "exports": {
@@ -223,10 +223,7 @@ export function inferProviderFromModel(model: string): string | undefined {
223
223
  if (model.startsWith("accounts/fireworks/models/")) {
224
224
  return "fireworks";
225
225
  }
226
- if (
227
- model.startsWith("openai/gpt-5.6") ||
228
- model.startsWith("openai/gpt-6-astra")
229
- ) {
226
+ if (model.startsWith("openai/gpt-5.6")) {
230
227
  // Listed by OpenRouter (#37856), the earlier catalog entry; the Vercel
231
228
  // AI Gateway does not carry these IDs.
232
229
  return "openrouter";