@vellumai/assistant 0.11.9-dev.202609081913.93e93af → 0.11.9-dev.202609082015.1ff08e1
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/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/plan-credit.test.ts +51 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/plan-credit.ts +66 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/plan-credit.test.ts +51 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/plan-credit.ts +66 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/plan-credit.test.ts +51 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/plan-credit.ts +66 -0
- package/openapi.yaml +72 -5
- package/package.json +1 -1
- package/src/__tests__/mcp-config-secret-boundary.test.ts +2 -0
- package/src/__tests__/memory-config-file-parity.test.ts +18 -0
- package/src/api/constants/personality-sliders.test.ts +21 -0
- package/src/api/constants/personality-sliders.ts +64 -0
- package/src/api/index.ts +8 -0
- package/src/calls/voice-session-bridge.ts +26 -0
- package/src/cli/commands/config.help.ts +3 -1
- package/src/cli/commands/memory/worker.ts +1 -1
- package/src/cli/commands/platform/__tests__/credits-format.test.ts +94 -5
- package/src/cli/commands/platform/__tests__/credits.test.ts +10 -0
- package/src/cli/commands/platform/credits-format.ts +57 -0
- package/src/cli/commands/platform/index.help.ts +19 -3
- package/src/config/schemas/memory-storage.test.ts +39 -0
- package/src/config/schemas/memory-storage.ts +21 -0
- package/src/daemon/__tests__/embedding-reconcile.test.ts +77 -0
- package/src/daemon/__tests__/lifecycle-embedding-reconcile.test.ts +3 -0
- package/src/daemon/embedding-reconcile.ts +64 -1
- package/src/daemon/handlers/config-embeddings.ts +31 -0
- package/src/live-voice/__tests__/live-voice-photo.test.ts +72 -0
- package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +81 -0
- package/src/live-voice/live-voice-photo.ts +68 -4
- package/src/live-voice/live-voice-session.ts +36 -2
- package/src/live-voice/protocol.ts +98 -1
- package/src/persistence/conversation-crud.ts +38 -0
- package/src/persistence/embeddings/embedding-backend.test.ts +162 -0
- package/src/persistence/embeddings/embedding-backend.ts +148 -11
- package/src/persistence/embeddings/embedding-openai.test.ts +113 -0
- package/src/persistence/embeddings/embedding-openai.ts +55 -4
- package/src/persistence/embeddings/embedding-types.test.ts +24 -0
- package/src/persistence/embeddings/embedding-types.ts +25 -1
- package/src/persistence/job-utils.ts +6 -2
- package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +1 -0
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +11 -3
- package/src/plugins/defaults/memory/src/__tests__/memory-worker-routes.test.ts +20 -0
- package/src/plugins/defaults/memory/src/memory-worker-routes.ts +3 -1
- package/src/plugins/defaults/memory/substrate/__tests__/reembed-job.test.ts +1 -0
- package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +1 -0
- package/src/plugins/defaults/memory/v3/__tests__/section-dense-store.test.ts +82 -0
- package/src/plugins/defaults/memory/v3/section-dense-store.ts +9 -27
- package/src/providers/__tests__/provider-secret-catalog.test.ts +4 -0
- package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +51 -0
- package/src/providers/openai/chat-completions-provider.ts +24 -4
- package/src/providers/provider-secret-catalog.ts +11 -1
- package/src/providers/vellum/client.ts +14 -1
- package/src/providers/vellum/personality-directions.test.ts +163 -0
- package/src/providers/vellum/personality-directions.ts +120 -0
- package/src/runtime/routes/__tests__/platform-credits-routes.test.ts +99 -5
- package/src/runtime/routes/conversation-query-routes.ts +34 -4
- package/src/runtime/routes/platform-routes.ts +121 -24
package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json
CHANGED
|
@@ -26,7 +26,8 @@
|
|
|
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"
|
|
29
|
+
"./platform-credential": "./src/platform-credential.ts",
|
|
30
|
+
"./plan-credit": "./src/plan-credit.ts"
|
|
30
31
|
},
|
|
31
32
|
"scripts": {
|
|
32
33
|
"typecheck": "bunx tsc --noEmit",
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
extraCreditUsd,
|
|
5
|
+
planCreditUsedFraction,
|
|
6
|
+
usageGrantRatio,
|
|
7
|
+
} from "../plan-credit.js";
|
|
8
|
+
|
|
9
|
+
describe("usageGrantRatio", () => {
|
|
10
|
+
test("reads the used share and clamps to 0..1", () => {
|
|
11
|
+
expect(usageGrantRatio(20, 9.1)).toBeCloseTo(0.545);
|
|
12
|
+
expect(usageGrantRatio(20, 0)).toBe(1);
|
|
13
|
+
expect(usageGrantRatio(20, 25)).toBe(0);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("has no reading without both figures or with nothing granted", () => {
|
|
17
|
+
expect(usageGrantRatio(null, 5)).toBeNull();
|
|
18
|
+
expect(usageGrantRatio(20, null)).toBeNull();
|
|
19
|
+
expect(usageGrantRatio(0, 0)).toBeNull();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("planCreditUsedFraction", () => {
|
|
24
|
+
test("prefers the ratio whatever the plan", () => {
|
|
25
|
+
expect(planCreditUsedFraction(20, 9.1, "base")).toBeCloseTo(0.545);
|
|
26
|
+
expect(planCreditUsedFraction(20, 9.1, null)).toBeCloseTo(0.545);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("treats a Pro plan with nothing granted as fully spent", () => {
|
|
30
|
+
expect(planCreditUsedFraction(0, 0, "pro")).toBe(1);
|
|
31
|
+
expect(planCreditUsedFraction(0, null, "pro")).toBe(1);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("gives a base or unknown plan with nothing granted no reading", () => {
|
|
35
|
+
expect(planCreditUsedFraction(0, 0, "base")).toBeNull();
|
|
36
|
+
expect(planCreditUsedFraction(0, 0, null)).toBeNull();
|
|
37
|
+
expect(planCreditUsedFraction(null, null, "pro")).toBeNull();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("extraCreditUsd", () => {
|
|
42
|
+
test("nets unused grant credit out of the balance to the cent", () => {
|
|
43
|
+
expect(extraCreditUsd(42.17, 9.1)).toBe(33.07);
|
|
44
|
+
expect(extraCreditUsd(34.65, 9.1)).toBe(25.55);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("never goes below zero", () => {
|
|
48
|
+
expect(extraCreditUsd(5, 9.1)).toBe(0);
|
|
49
|
+
expect(extraCreditUsd(-2.5, 0)).toBe(0);
|
|
50
|
+
});
|
|
51
|
+
});
|
package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ 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";
|
|
31
32
|
export * from "./platform-credential.js";
|
|
32
33
|
export * from "./remote-web-pairing.js";
|
|
33
34
|
export * from "./twilio-ingress.js";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan-credit derivations shared by the assistant runtime's `platform credits`
|
|
3
|
+
* route and the web client's usage meter, so both read the billing summary's
|
|
4
|
+
* grant figures the same way and can never quote different readings.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type BillingPlanId = "base" | "pro";
|
|
8
|
+
|
|
9
|
+
function clamp01(value: number): number {
|
|
10
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
return value > 1 ? 1 : value;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* How much of the usage credit an account was granted it has already used:
|
|
18
|
+
* the granted total less what is still unused, over that total. The initial
|
|
19
|
+
* $5 grant burns 0 to 100% as it is spent, and a further grant grows the total
|
|
20
|
+
* so the bar drops back. Null when nothing was ever granted, or when the
|
|
21
|
+
* platform reports neither figure, which has no honest reading rather than a
|
|
22
|
+
* full or empty bar.
|
|
23
|
+
*/
|
|
24
|
+
export function usageGrantRatio(
|
|
25
|
+
totalUsd: number | null,
|
|
26
|
+
availableUsd: number | null,
|
|
27
|
+
): number | null {
|
|
28
|
+
if (totalUsd == null || availableUsd == null || totalUsd <= 0) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return clamp01((totalUsd - availableUsd) / totalUsd);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The plan-credit reading with the plan's fallback applied. The grant figures
|
|
36
|
+
* count only unexpired grants, so a Pro subscription whose grants total
|
|
37
|
+
* nothing has used or expired everything it was granted (a full bar, with
|
|
38
|
+
* nothing scheduled to refill it), while a base plan in that position was
|
|
39
|
+
* never granted anything (no reading). An unknown plan gets the ratio when
|
|
40
|
+
* the figures allow one and no fallback otherwise.
|
|
41
|
+
*/
|
|
42
|
+
export function planCreditUsedFraction(
|
|
43
|
+
totalUsd: number | null,
|
|
44
|
+
availableUsd: number | null,
|
|
45
|
+
planId: BillingPlanId | null,
|
|
46
|
+
): number | null {
|
|
47
|
+
const ratio = usageGrantRatio(totalUsd, availableUsd);
|
|
48
|
+
if (ratio != null) {
|
|
49
|
+
return ratio;
|
|
50
|
+
}
|
|
51
|
+
if (planId === "pro" && totalUsd != null && totalUsd <= 0) {
|
|
52
|
+
return 1;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Credit bought or earned on top of the plan-included grants: the balance less
|
|
59
|
+
* whatever is still unused on those grants, never below zero, to the cent.
|
|
60
|
+
*/
|
|
61
|
+
export function extraCreditUsd(
|
|
62
|
+
balanceUsd: number,
|
|
63
|
+
availableUsd: number,
|
|
64
|
+
): number {
|
|
65
|
+
return Math.round(Math.max(0, balanceUsd - availableUsd) * 100) / 100;
|
|
66
|
+
}
|
package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json
CHANGED
|
@@ -26,7 +26,8 @@
|
|
|
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"
|
|
29
|
+
"./platform-credential": "./src/platform-credential.ts",
|
|
30
|
+
"./plan-credit": "./src/plan-credit.ts"
|
|
30
31
|
},
|
|
31
32
|
"scripts": {
|
|
32
33
|
"typecheck": "bunx tsc --noEmit",
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
extraCreditUsd,
|
|
5
|
+
planCreditUsedFraction,
|
|
6
|
+
usageGrantRatio,
|
|
7
|
+
} from "../plan-credit.js";
|
|
8
|
+
|
|
9
|
+
describe("usageGrantRatio", () => {
|
|
10
|
+
test("reads the used share and clamps to 0..1", () => {
|
|
11
|
+
expect(usageGrantRatio(20, 9.1)).toBeCloseTo(0.545);
|
|
12
|
+
expect(usageGrantRatio(20, 0)).toBe(1);
|
|
13
|
+
expect(usageGrantRatio(20, 25)).toBe(0);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("has no reading without both figures or with nothing granted", () => {
|
|
17
|
+
expect(usageGrantRatio(null, 5)).toBeNull();
|
|
18
|
+
expect(usageGrantRatio(20, null)).toBeNull();
|
|
19
|
+
expect(usageGrantRatio(0, 0)).toBeNull();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("planCreditUsedFraction", () => {
|
|
24
|
+
test("prefers the ratio whatever the plan", () => {
|
|
25
|
+
expect(planCreditUsedFraction(20, 9.1, "base")).toBeCloseTo(0.545);
|
|
26
|
+
expect(planCreditUsedFraction(20, 9.1, null)).toBeCloseTo(0.545);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("treats a Pro plan with nothing granted as fully spent", () => {
|
|
30
|
+
expect(planCreditUsedFraction(0, 0, "pro")).toBe(1);
|
|
31
|
+
expect(planCreditUsedFraction(0, null, "pro")).toBe(1);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("gives a base or unknown plan with nothing granted no reading", () => {
|
|
35
|
+
expect(planCreditUsedFraction(0, 0, "base")).toBeNull();
|
|
36
|
+
expect(planCreditUsedFraction(0, 0, null)).toBeNull();
|
|
37
|
+
expect(planCreditUsedFraction(null, null, "pro")).toBeNull();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("extraCreditUsd", () => {
|
|
42
|
+
test("nets unused grant credit out of the balance to the cent", () => {
|
|
43
|
+
expect(extraCreditUsd(42.17, 9.1)).toBe(33.07);
|
|
44
|
+
expect(extraCreditUsd(34.65, 9.1)).toBe(25.55);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("never goes below zero", () => {
|
|
48
|
+
expect(extraCreditUsd(5, 9.1)).toBe(0);
|
|
49
|
+
expect(extraCreditUsd(-2.5, 0)).toBe(0);
|
|
50
|
+
});
|
|
51
|
+
});
|
package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ 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";
|
|
31
32
|
export * from "./platform-credential.js";
|
|
32
33
|
export * from "./remote-web-pairing.js";
|
|
33
34
|
export * from "./twilio-ingress.js";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan-credit derivations shared by the assistant runtime's `platform credits`
|
|
3
|
+
* route and the web client's usage meter, so both read the billing summary's
|
|
4
|
+
* grant figures the same way and can never quote different readings.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type BillingPlanId = "base" | "pro";
|
|
8
|
+
|
|
9
|
+
function clamp01(value: number): number {
|
|
10
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
return value > 1 ? 1 : value;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* How much of the usage credit an account was granted it has already used:
|
|
18
|
+
* the granted total less what is still unused, over that total. The initial
|
|
19
|
+
* $5 grant burns 0 to 100% as it is spent, and a further grant grows the total
|
|
20
|
+
* so the bar drops back. Null when nothing was ever granted, or when the
|
|
21
|
+
* platform reports neither figure, which has no honest reading rather than a
|
|
22
|
+
* full or empty bar.
|
|
23
|
+
*/
|
|
24
|
+
export function usageGrantRatio(
|
|
25
|
+
totalUsd: number | null,
|
|
26
|
+
availableUsd: number | null,
|
|
27
|
+
): number | null {
|
|
28
|
+
if (totalUsd == null || availableUsd == null || totalUsd <= 0) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return clamp01((totalUsd - availableUsd) / totalUsd);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The plan-credit reading with the plan's fallback applied. The grant figures
|
|
36
|
+
* count only unexpired grants, so a Pro subscription whose grants total
|
|
37
|
+
* nothing has used or expired everything it was granted (a full bar, with
|
|
38
|
+
* nothing scheduled to refill it), while a base plan in that position was
|
|
39
|
+
* never granted anything (no reading). An unknown plan gets the ratio when
|
|
40
|
+
* the figures allow one and no fallback otherwise.
|
|
41
|
+
*/
|
|
42
|
+
export function planCreditUsedFraction(
|
|
43
|
+
totalUsd: number | null,
|
|
44
|
+
availableUsd: number | null,
|
|
45
|
+
planId: BillingPlanId | null,
|
|
46
|
+
): number | null {
|
|
47
|
+
const ratio = usageGrantRatio(totalUsd, availableUsd);
|
|
48
|
+
if (ratio != null) {
|
|
49
|
+
return ratio;
|
|
50
|
+
}
|
|
51
|
+
if (planId === "pro" && totalUsd != null && totalUsd <= 0) {
|
|
52
|
+
return 1;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Credit bought or earned on top of the plan-included grants: the balance less
|
|
59
|
+
* whatever is still unused on those grants, never below zero, to the cent.
|
|
60
|
+
*/
|
|
61
|
+
export function extraCreditUsd(
|
|
62
|
+
balanceUsd: number,
|
|
63
|
+
availableUsd: number,
|
|
64
|
+
): number {
|
|
65
|
+
return Math.round(Math.max(0, balanceUsd - availableUsd) * 100) / 100;
|
|
66
|
+
}
|
|
@@ -26,7 +26,8 @@
|
|
|
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"
|
|
29
|
+
"./platform-credential": "./src/platform-credential.ts",
|
|
30
|
+
"./plan-credit": "./src/plan-credit.ts"
|
|
30
31
|
},
|
|
31
32
|
"scripts": {
|
|
32
33
|
"typecheck": "bunx tsc --noEmit",
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
extraCreditUsd,
|
|
5
|
+
planCreditUsedFraction,
|
|
6
|
+
usageGrantRatio,
|
|
7
|
+
} from "../plan-credit.js";
|
|
8
|
+
|
|
9
|
+
describe("usageGrantRatio", () => {
|
|
10
|
+
test("reads the used share and clamps to 0..1", () => {
|
|
11
|
+
expect(usageGrantRatio(20, 9.1)).toBeCloseTo(0.545);
|
|
12
|
+
expect(usageGrantRatio(20, 0)).toBe(1);
|
|
13
|
+
expect(usageGrantRatio(20, 25)).toBe(0);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("has no reading without both figures or with nothing granted", () => {
|
|
17
|
+
expect(usageGrantRatio(null, 5)).toBeNull();
|
|
18
|
+
expect(usageGrantRatio(20, null)).toBeNull();
|
|
19
|
+
expect(usageGrantRatio(0, 0)).toBeNull();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("planCreditUsedFraction", () => {
|
|
24
|
+
test("prefers the ratio whatever the plan", () => {
|
|
25
|
+
expect(planCreditUsedFraction(20, 9.1, "base")).toBeCloseTo(0.545);
|
|
26
|
+
expect(planCreditUsedFraction(20, 9.1, null)).toBeCloseTo(0.545);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("treats a Pro plan with nothing granted as fully spent", () => {
|
|
30
|
+
expect(planCreditUsedFraction(0, 0, "pro")).toBe(1);
|
|
31
|
+
expect(planCreditUsedFraction(0, null, "pro")).toBe(1);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("gives a base or unknown plan with nothing granted no reading", () => {
|
|
35
|
+
expect(planCreditUsedFraction(0, 0, "base")).toBeNull();
|
|
36
|
+
expect(planCreditUsedFraction(0, 0, null)).toBeNull();
|
|
37
|
+
expect(planCreditUsedFraction(null, null, "pro")).toBeNull();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("extraCreditUsd", () => {
|
|
42
|
+
test("nets unused grant credit out of the balance to the cent", () => {
|
|
43
|
+
expect(extraCreditUsd(42.17, 9.1)).toBe(33.07);
|
|
44
|
+
expect(extraCreditUsd(34.65, 9.1)).toBe(25.55);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("never goes below zero", () => {
|
|
48
|
+
expect(extraCreditUsd(5, 9.1)).toBe(0);
|
|
49
|
+
expect(extraCreditUsd(-2.5, 0)).toBe(0);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -28,6 +28,7 @@ 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";
|
|
31
32
|
export * from "./platform-credential.js";
|
|
32
33
|
export * from "./remote-web-pairing.js";
|
|
33
34
|
export * from "./twilio-ingress.js";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan-credit derivations shared by the assistant runtime's `platform credits`
|
|
3
|
+
* route and the web client's usage meter, so both read the billing summary's
|
|
4
|
+
* grant figures the same way and can never quote different readings.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type BillingPlanId = "base" | "pro";
|
|
8
|
+
|
|
9
|
+
function clamp01(value: number): number {
|
|
10
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
return value > 1 ? 1 : value;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* How much of the usage credit an account was granted it has already used:
|
|
18
|
+
* the granted total less what is still unused, over that total. The initial
|
|
19
|
+
* $5 grant burns 0 to 100% as it is spent, and a further grant grows the total
|
|
20
|
+
* so the bar drops back. Null when nothing was ever granted, or when the
|
|
21
|
+
* platform reports neither figure, which has no honest reading rather than a
|
|
22
|
+
* full or empty bar.
|
|
23
|
+
*/
|
|
24
|
+
export function usageGrantRatio(
|
|
25
|
+
totalUsd: number | null,
|
|
26
|
+
availableUsd: number | null,
|
|
27
|
+
): number | null {
|
|
28
|
+
if (totalUsd == null || availableUsd == null || totalUsd <= 0) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return clamp01((totalUsd - availableUsd) / totalUsd);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The plan-credit reading with the plan's fallback applied. The grant figures
|
|
36
|
+
* count only unexpired grants, so a Pro subscription whose grants total
|
|
37
|
+
* nothing has used or expired everything it was granted (a full bar, with
|
|
38
|
+
* nothing scheduled to refill it), while a base plan in that position was
|
|
39
|
+
* never granted anything (no reading). An unknown plan gets the ratio when
|
|
40
|
+
* the figures allow one and no fallback otherwise.
|
|
41
|
+
*/
|
|
42
|
+
export function planCreditUsedFraction(
|
|
43
|
+
totalUsd: number | null,
|
|
44
|
+
availableUsd: number | null,
|
|
45
|
+
planId: BillingPlanId | null,
|
|
46
|
+
): number | null {
|
|
47
|
+
const ratio = usageGrantRatio(totalUsd, availableUsd);
|
|
48
|
+
if (ratio != null) {
|
|
49
|
+
return ratio;
|
|
50
|
+
}
|
|
51
|
+
if (planId === "pro" && totalUsd != null && totalUsd <= 0) {
|
|
52
|
+
return 1;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Credit bought or earned on top of the plan-included grants: the balance less
|
|
59
|
+
* whatever is still unused on those grants, never below zero, to the cent.
|
|
60
|
+
*/
|
|
61
|
+
export function extraCreditUsd(
|
|
62
|
+
balanceUsd: number,
|
|
63
|
+
availableUsd: number,
|
|
64
|
+
): number {
|
|
65
|
+
return Math.round(Math.max(0, balanceUsd - availableUsd) * 100) / 100;
|
|
66
|
+
}
|
package/openapi.yaml
CHANGED
|
@@ -5102,7 +5102,7 @@ paths:
|
|
|
5102
5102
|
put:
|
|
5103
5103
|
operationId: config_embeddings_put
|
|
5104
5104
|
summary: Set embedding config
|
|
5105
|
-
description: Change the embedding provider and
|
|
5105
|
+
description: Change the embedding provider, model, and optional custom endpoint.
|
|
5106
5106
|
tags:
|
|
5107
5107
|
- config
|
|
5108
5108
|
requestBody:
|
|
@@ -5116,6 +5116,14 @@ paths:
|
|
|
5116
5116
|
type: string
|
|
5117
5117
|
model:
|
|
5118
5118
|
type: string
|
|
5119
|
+
baseUrl:
|
|
5120
|
+
type: string
|
|
5121
|
+
dimensions:
|
|
5122
|
+
anyOf:
|
|
5123
|
+
- type: integer
|
|
5124
|
+
exclusiveMinimum: 0
|
|
5125
|
+
maximum: 9007199254740991
|
|
5126
|
+
- type: "null"
|
|
5119
5127
|
required:
|
|
5120
5128
|
- provider
|
|
5121
5129
|
responses:
|
|
@@ -20044,6 +20052,7 @@ paths:
|
|
|
20044
20052
|
- openai
|
|
20045
20053
|
- gemini
|
|
20046
20054
|
- ollama
|
|
20055
|
+
- custom
|
|
20047
20056
|
- type: "null"
|
|
20048
20057
|
model:
|
|
20049
20058
|
anyOf:
|
|
@@ -24668,12 +24677,13 @@ paths:
|
|
|
24668
24677
|
/v1/platform/credits:
|
|
24669
24678
|
get:
|
|
24670
24679
|
operationId: platform_credits_get
|
|
24671
|
-
summary: Get the organization's
|
|
24680
|
+
summary: Get the organization's credit balance, plan-credit usage, and daily-limit state
|
|
24672
24681
|
description:
|
|
24673
24682
|
"Fetches the org's settled, pending, and effective (remaining) credit balance in USD from the platform
|
|
24674
|
-
billing summary, plus
|
|
24675
|
-
|
|
24676
|
-
|
|
24683
|
+
billing summary, plus plan-included credit usage (remaining, total, and the used fraction shown by the in-app
|
|
24684
|
+
usage meter), extra credit bought or earned on top, credit expiring within 30 days, and the daily-limit state:
|
|
24685
|
+
today's spend counted against the daily credit limit (which excludes spend covered by plan-included credits, so
|
|
24686
|
+
it is not total spend), the limit itself, and the low-balance warning state."
|
|
24677
24687
|
tags:
|
|
24678
24688
|
- platform
|
|
24679
24689
|
responses:
|
|
@@ -24724,6 +24734,56 @@ paths:
|
|
|
24724
24734
|
low_balance_warning:
|
|
24725
24735
|
type: boolean
|
|
24726
24736
|
description: True when the balance is above zero but below the low-balance threshold and auto top-up is not enabled.
|
|
24737
|
+
plan_credit_remaining:
|
|
24738
|
+
anyOf:
|
|
24739
|
+
- type: number
|
|
24740
|
+
- type: "null"
|
|
24741
|
+
description:
|
|
24742
|
+
Unused credit (USD) remaining on the unexpired plan-included grants (initial credit, Pro credit bundle).
|
|
24743
|
+
Null when the platform did not report grant figures.
|
|
24744
|
+
plan_credit_total:
|
|
24745
|
+
anyOf:
|
|
24746
|
+
- type: number
|
|
24747
|
+
- type: "null"
|
|
24748
|
+
description:
|
|
24749
|
+
Total credit (USD) those plan-included grants were worth, net of refunds. Null when the platform did not
|
|
24750
|
+
report grant figures.
|
|
24751
|
+
plan_credit_used_fraction:
|
|
24752
|
+
anyOf:
|
|
24753
|
+
- type: number
|
|
24754
|
+
- type: "null"
|
|
24755
|
+
description:
|
|
24756
|
+
"Share of the plan-included credit already used, from 0 to 1: the same reading as the in-app usage meter. A
|
|
24757
|
+
Pro subscription whose unexpired grants total nothing reads as 1 (everything granted is used or
|
|
24758
|
+
expired). Null when there is no usable reading: grant figures missing, or a zero total on a base
|
|
24759
|
+
or unknown plan."
|
|
24760
|
+
plan_credits_spent:
|
|
24761
|
+
anyOf:
|
|
24762
|
+
- type: boolean
|
|
24763
|
+
- type: "null"
|
|
24764
|
+
description:
|
|
24765
|
+
True when the plan-included credit is used up or expired. Whether further managed usage is funded is
|
|
24766
|
+
extra_credit_remaining (zero means the organization is out of credit). Null when there is no
|
|
24767
|
+
plan-credit reading.
|
|
24768
|
+
extra_credit_remaining:
|
|
24769
|
+
anyOf:
|
|
24770
|
+
- type: number
|
|
24771
|
+
- type: "null"
|
|
24772
|
+
description:
|
|
24773
|
+
"Credit (USD) bought or earned on top of the plan-included grants: remaining minus plan_credit_remaining,
|
|
24774
|
+
floored at zero. Null when grant figures are missing."
|
|
24775
|
+
credits_expiring_soon:
|
|
24776
|
+
anyOf:
|
|
24777
|
+
- type: number
|
|
24778
|
+
- type: "null"
|
|
24779
|
+
description:
|
|
24780
|
+
Unexpired credit (USD) on grants that expire within the next 30 days. Null when the platform did not report
|
|
24781
|
+
it.
|
|
24782
|
+
next_credit_expiry_at:
|
|
24783
|
+
anyOf:
|
|
24784
|
+
- type: string
|
|
24785
|
+
- type: "null"
|
|
24786
|
+
description: Earliest upcoming expiry (ISO 8601) across grants that still hold credit, or null when none is scheduled.
|
|
24727
24787
|
required:
|
|
24728
24788
|
- remaining
|
|
24729
24789
|
- settled
|
|
@@ -24737,6 +24797,13 @@ paths:
|
|
|
24737
24797
|
- daily_limit_snoozed
|
|
24738
24798
|
- low_balance_threshold
|
|
24739
24799
|
- low_balance_warning
|
|
24800
|
+
- plan_credit_remaining
|
|
24801
|
+
- plan_credit_total
|
|
24802
|
+
- plan_credit_used_fraction
|
|
24803
|
+
- plan_credits_spent
|
|
24804
|
+
- extra_credit_remaining
|
|
24805
|
+
- credits_expiring_soon
|
|
24806
|
+
- next_credit_expiry_at
|
|
24740
24807
|
additionalProperties: false
|
|
24741
24808
|
/v1/platform/disconnect:
|
|
24742
24809
|
post:
|
package/package.json
CHANGED
|
@@ -82,6 +82,8 @@ mock.module("../persistence/embeddings/embedding-backend.js", () => ({
|
|
|
82
82
|
vectors: [],
|
|
83
83
|
}),
|
|
84
84
|
geminiCacheExtras: () => [],
|
|
85
|
+
customCacheExtras: () => [],
|
|
86
|
+
durableEmbeddingCacheExtras: () => [],
|
|
85
87
|
generateSparseEmbedding: () => ({ indices: [], values: [] }),
|
|
86
88
|
getMemoryBackendStatus: async () => ({
|
|
87
89
|
enabled: false,
|
|
@@ -101,6 +101,24 @@ describe("memory config file parity", () => {
|
|
|
101
101
|
expect(memory.embeddings.provider).toBe("openai");
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
+
test("custom embedding endpoint knobs are visible and identical", () => {
|
|
105
|
+
writeConfig({
|
|
106
|
+
memory: {
|
|
107
|
+
embeddings: {
|
|
108
|
+
provider: "custom",
|
|
109
|
+
baseUrl: "http://127.0.0.1:4000/v1",
|
|
110
|
+
customModel: "text-embedding-3-small",
|
|
111
|
+
customDimensions: 1024,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
const memory = expectParity();
|
|
116
|
+
expect(memory.embeddings.provider).toBe("custom");
|
|
117
|
+
expect(memory.embeddings.baseUrl).toBe("http://127.0.0.1:4000/v1");
|
|
118
|
+
expect(memory.embeddings.customModel).toBe("text-embedding-3-small");
|
|
119
|
+
expect(memory.embeddings.customDimensions).toBe(1024);
|
|
120
|
+
});
|
|
121
|
+
|
|
104
122
|
test("cross-field invariant: segmentation overlap >= target falls back like the loader", () => {
|
|
105
123
|
writeConfig({
|
|
106
124
|
memory: {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
PERSONALITY_AXIS_IDS,
|
|
5
|
+
PERSONALITY_DIRECTION_AXES,
|
|
6
|
+
PERSONALITY_SLIDER_DEFAULT,
|
|
7
|
+
PERSONALITY_SLIDERS_PATH,
|
|
8
|
+
} from "./personality-sliders.js";
|
|
9
|
+
|
|
10
|
+
describe("personality slider contract", () => {
|
|
11
|
+
test("sidecar path and default stay centered", () => {
|
|
12
|
+
expect(PERSONALITY_SLIDERS_PATH).toBe("data/personality-sliders.json");
|
|
13
|
+
expect(PERSONALITY_SLIDER_DEFAULT).toBe(50);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("every slider axis has a left and right direction pole", () => {
|
|
17
|
+
expect(PERSONALITY_DIRECTION_AXES.map((axis) => axis.sliderId)).toEqual(
|
|
18
|
+
Object.values(PERSONALITY_AXIS_IDS),
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Personality slider sidecar path, the five 0-100 axis ids, and the
|
|
3
|
+
* hosted-Qwen direction poles those sliders map onto.
|
|
4
|
+
*
|
|
5
|
+
* The web writes `data/personality-sliders.json`. The assistant reads the
|
|
6
|
+
* same path and maps each slider onto one left/right pole. Both import
|
|
7
|
+
* these constants from `@vellumai/assistant-api` so the ids cannot drift.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Workspace-relative sidecar holding the five 0-100 slider values. */
|
|
11
|
+
export const PERSONALITY_SLIDERS_PATH = "data/personality-sliders.json";
|
|
12
|
+
|
|
13
|
+
/** Sliders start centered. Center is no steer on the hosted-Qwen route. */
|
|
14
|
+
export const PERSONALITY_SLIDER_DEFAULT = 50;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Axis ids the personality sliders key their values by. Each is 0-100 with
|
|
18
|
+
* 0 = the left label and 100 = the right label.
|
|
19
|
+
*/
|
|
20
|
+
export const PERSONALITY_AXIS_IDS = {
|
|
21
|
+
companionCoworker: "companion-coworker",
|
|
22
|
+
genzBoomer: "genz-boomer",
|
|
23
|
+
executeCollaborate: "execute-collaborate",
|
|
24
|
+
playfulSerious: "playful-serious",
|
|
25
|
+
politeUnfiltered: "polite-unfiltered",
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
export type PersonalityAxisId =
|
|
29
|
+
(typeof PERSONALITY_AXIS_IDS)[keyof typeof PERSONALITY_AXIS_IDS];
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* One-sided direction poles for each slider. Center (50) activates neither.
|
|
33
|
+
* Values below 50 activate `left`; values above 50 activate `right`.
|
|
34
|
+
*/
|
|
35
|
+
export const PERSONALITY_DIRECTION_AXES = [
|
|
36
|
+
{
|
|
37
|
+
sliderId: PERSONALITY_AXIS_IDS.companionCoworker,
|
|
38
|
+
left: "companion",
|
|
39
|
+
right: "coworker",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
sliderId: PERSONALITY_AXIS_IDS.genzBoomer,
|
|
43
|
+
left: "genz",
|
|
44
|
+
right: "boomer",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
sliderId: PERSONALITY_AXIS_IDS.executeCollaborate,
|
|
48
|
+
left: "independent",
|
|
49
|
+
right: "collaborative",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
sliderId: PERSONALITY_AXIS_IDS.playfulSerious,
|
|
53
|
+
left: "playful",
|
|
54
|
+
right: "serious",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
sliderId: PERSONALITY_AXIS_IDS.politeUnfiltered,
|
|
58
|
+
left: "polite",
|
|
59
|
+
right: "unfiltered",
|
|
60
|
+
},
|
|
61
|
+
] as const;
|
|
62
|
+
|
|
63
|
+
export type PersonalityDirectionAxis =
|
|
64
|
+
(typeof PERSONALITY_DIRECTION_AXES)[number];
|