@memberjunction/ai-systemone 6.2.0-edge.4 → 6.2.0-edge.6
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/README.md +56 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/models/perplexityDecision.d.ts +8 -36
- package/dist/models/perplexityDecision.d.ts.map +1 -1
- package/dist/models/perplexityDecision.js +13 -65
- package/dist/models/perplexityDecision.js.map +1 -1
- package/dist/models/subqDecision.d.ts +37 -0
- package/dist/models/subqDecision.d.ts.map +1 -0
- package/dist/models/subqDecision.js +70 -0
- package/dist/models/subqDecision.js.map +1 -0
- package/dist/models/systemOneDecision.js +3 -24
- package/dist/models/systemOneDecision.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# @memberjunction/ai-systemone
|
|
2
2
|
|
|
3
|
-
MemberJunction drivers for decision APIs that speak TypeSafe's System One decisions format. It ships
|
|
3
|
+
MemberJunction drivers for decision APIs that speak TypeSafe's System One decisions format. It ships three `BaseDecision` drivers:
|
|
4
4
|
|
|
5
5
|
- **`SystemOneDecision`**, for any server that answers `POST {base}/v1/systemone` (below);
|
|
6
|
-
- **`PerplexityDecision`**, for Perplexity's Decisions API and its `pplx-decider-v1-27b` model (see [Perplexity's Decider](#perplexitydecision-perplexitys-decider))
|
|
6
|
+
- **`PerplexityDecision`**, for Perplexity's Decisions API and its `pplx-decider-v1-27b` model (see [Perplexity's Decider](#perplexitydecision-perplexitys-decider));
|
|
7
|
+
- **`SubQDecision`**, for Subquadratic's SubQ Decisions API and its `subq-snap-preview` model (see [SubQ Snap](#subqdecision-subq-snap)).
|
|
7
8
|
|
|
8
9
|
`SystemOneDecision` covers three kinds of server:
|
|
9
10
|
|
|
@@ -26,12 +27,14 @@ graph TD
|
|
|
26
27
|
C["CloudflareDecision<br/>(@memberjunction/ai-cloudflare)"] -->|extends| B
|
|
27
28
|
D["OpenRouterDecision<br/>(@memberjunction/ai-openrouter)"] -->|extends| B
|
|
28
29
|
P["PerplexityDecision<br/>(@memberjunction/ai-systemone)"] -->|extends| B
|
|
30
|
+
Q["SubQDecision<br/>(@memberjunction/ai-systemone)"] -->|extends| B
|
|
29
31
|
B -->|extends| E["BaseDecision<br/>(@memberjunction/ai)"]
|
|
30
32
|
A -->|POST /v1/systemone| F["Kev on Modal · llama-server · TypeSafe"]
|
|
31
33
|
P -->|POST /v1/decisions| G["Perplexity Decisions API<br/>(pplx-decider-v1-27b)"]
|
|
34
|
+
Q -->|POST /v1/systemone| H["SubQ Decisions API<br/>(subq-snap-preview)"]
|
|
32
35
|
```
|
|
33
36
|
|
|
34
|
-
`BaseSystemOneDecision` owns the System One request and answer mapping. `SystemOneDecision` adds the endpoint, the optional token and error messages that name what the server said. `PerplexityDecision` adds
|
|
37
|
+
`BaseSystemOneDecision` owns the System One request and answer mapping. `SystemOneDecision` adds the endpoint, the optional token and error messages that name what the server said. `PerplexityDecision` and `SubQDecision` extend `BaseHostedSystemOneDecision`, which adds the fixed endpoint, the key check and the vendor's error messages; each supplies only its vendor's facts.
|
|
35
38
|
|
|
36
39
|
## Configuration
|
|
37
40
|
|
|
@@ -154,9 +157,55 @@ const result = await decider.Decide({
|
|
|
154
157
|
- A `400` is classified from its message. An unknown model is an `InvalidRequest`, which stops the loop.
|
|
155
158
|
- A `413` (a body over 32 MiB) is an `Unknown` error, which fails over. MJ sends no images, so its requests stay far below that size.
|
|
156
159
|
|
|
160
|
+
## `SubQDecision`: SubQ Snap
|
|
161
|
+
|
|
162
|
+
`SubQDecision` calls Subquadratic's SubQ Decisions API, `POST https://api.subq.ai/v1/systemone`, which serves SubQ Snap, a multimodal decision model built for fast, long-context decisions. Subquadratic announced it on 2026-10-12, in **public preview**, as `subq-snap-preview`. In MJ's catalog it is the `SubQ Snap` model on the `Subquadratic` vendor. The API is its only host: it is not on OpenRouter.
|
|
163
|
+
|
|
164
|
+
The API speaks the System One format exactly and returns the response bare, so the driver adds only the endpoint, a check that there is a key, SubQ's error messages and the classification of the statuses SubQ documents.
|
|
165
|
+
|
|
166
|
+
| | |
|
|
167
|
+
|---|---|
|
|
168
|
+
| **Endpoint** | `https://api.subq.ai/v1/systemone`. A URL passed to the constructor wins, then a credential's `endpoint`. Either is the full request URL. |
|
|
169
|
+
| **Key** | A SubQ API key from console.subq.ai, sent as `Authorization: Bearer <key>`. |
|
|
170
|
+
| **Model** | `subq-snap-preview`, the row's `APIName` and the driver's default. The ID will change at general availability: change the row's `APIName` then; the model's name stays `SubQ Snap`. |
|
|
171
|
+
| **Limits** | 2 to 255 options per Choice and 2 to 10 levels per Score (set as the model's `Decision` limits); question names up to 100 characters. Subquadratic's announcement gives up to 384K tokens of context; its API documentation gives no limit, so none is set. |
|
|
172
|
+
| **Price** | $0.05 per million input tokens. Output is free: `usage.output_tokens` is always 0. |
|
|
173
|
+
|
|
174
|
+
**Configuration.** Bind an `API Key` AI Credential to the model's `Subquadratic` Inference Provider row (or to the `Subquadratic` vendor), or set the legacy variable:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
AI_VENDOR_API_KEY__SUBQDECISION=sk-...
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Usage.** Name the model and the vendor through `AIDecisionRunner`, or call the driver directly:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { SubQDecision } from '@memberjunction/ai-systemone';
|
|
184
|
+
|
|
185
|
+
const snap = new SubQDecision('your-subq-api-key');
|
|
186
|
+
const result = await snap.Decide({
|
|
187
|
+
Model: 'subq-snap-preview',
|
|
188
|
+
State: 'Patient with asthma reports a sore throat, fever since yesterday, and shortness of breath.',
|
|
189
|
+
Questions: {
|
|
190
|
+
escalate: { Kind: 'Likelihood', Instructions: 'Should a nurse see this chat before the patient books anything?' },
|
|
191
|
+
acuity: { Kind: 'Score', Instructions: 'How soon should someone respond?', Levels: ['Within a week', 'Within a day', 'Within an hour'] },
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**As a fallback.** `Default Decision`'s bindings are unchanged, but SubQ Snap, unmeasured in MJ, is its last power-matched fallback once its key resolves, because the fallbacks follow PowerRank distance from `Default Decision`'s target rank. A credential bound to the `Subquadratic` vendor, or a default `API Key` credential, gives its row a key; on such a host `Default Decision` can fail over to SubQ's preview API once every earlier candidate has failed. To prevent that, set the row's `Status` to `Inactive`.
|
|
197
|
+
|
|
198
|
+
**Errors and failover.**
|
|
199
|
+
|
|
200
|
+
- A missing key fails before any request with a `NoCredentials` error that allows failover.
|
|
201
|
+
- The message names SubQ's `detail.error_type` and `detail.message` (SubQ's `detail` is an object, unlike FastAPI's string or list).
|
|
202
|
+
- A `401` (a missing or invalid key) is an `Authentication` error. `ErrorAnalyzer` rates it fatal, which stops the failover loop, as for every other driver.
|
|
203
|
+
- A `402` (no credits) is a `NoCredit` error, and a `403` (the key cannot use the model) and a `422` (an invalid request, or a model that is not a decision model) are `ModelError`s. The driver sets these itself, so whatever SubQ's message says, they allow failover rather than stopping the loop. They are not vendor-level errors (`Authentication`, `VendorValidationError`), which would make the runner drop SubQ's other rows; it has none.
|
|
204
|
+
- A `429` and a `503` fail over. SubQ's advice is to retry both with backoff; `Default Decision` sets `MaxRetries` to 0, so it fails over at once.
|
|
205
|
+
|
|
157
206
|
## Not supported yet
|
|
158
207
|
|
|
159
|
-
- **Images.** llama.cpp, Clef and
|
|
208
|
+
- **Images.** llama.cpp, Clef, Perplexity's API and SubQ's API (up to 4 images) accept images with the state; MJ's `DecisionParams` has none, so no driver sends them.
|
|
160
209
|
|
|
161
210
|
## Class Registration
|
|
162
211
|
|
|
@@ -164,7 +213,9 @@ Registered as `SystemOneDecision` via `@RegisterClass(BaseDecision, 'SystemOneDe
|
|
|
164
213
|
|
|
165
214
|
Registered as `PerplexityDecision` via `@RegisterClass(BaseDecision, 'PerplexityDecision')`. The `Perplexity Decider v1 27B` model's `Perplexity` row names it as its `DriverClass`.
|
|
166
215
|
|
|
216
|
+
Registered as `SubQDecision` via `@RegisterClass(BaseDecision, 'SubQDecision')`. The `SubQ Snap` model's `Subquadratic` row names it as its `DriverClass`.
|
|
217
|
+
|
|
167
218
|
## Dependencies
|
|
168
219
|
|
|
169
|
-
- `@memberjunction/ai` - Core AI abstractions, including `BaseSystemOneDecision`
|
|
220
|
+
- `@memberjunction/ai` - Core AI abstractions, including `BaseSystemOneDecision` and `BaseHostedSystemOneDecision`
|
|
170
221
|
- `@memberjunction/global` - Class registration
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC"}
|
|
@@ -1,47 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BaseHostedSystemOneDecision } from '@memberjunction/ai';
|
|
2
2
|
/**
|
|
3
3
|
* A `BaseDecision` driver for Perplexity's Decisions API, `POST https://api.perplexity.ai/v1/decisions`,
|
|
4
|
-
* which serves
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* error messages.
|
|
8
|
-
*
|
|
9
|
-
* **Key.** A Perplexity API key, sent as `Authorization: Bearer <key>` (the API does not read
|
|
10
|
-
* `x-api-key`). A raw key or an `API Key` AI Credential's values in JSON (`{"apiKey":"…"}`).
|
|
11
|
-
*
|
|
12
|
-
* **Endpoint.** The constructor's URL, else the credential's `endpoint` (an `API Key with Endpoint`
|
|
13
|
-
* credential), else {@link PerplexityDecision.DEFAULT_ENDPOINT}. Each is the full request URL, unlike
|
|
14
|
-
* `SystemOneDecision`'s base URL. Trailing slashes are removed: the API answers `404` to a path with one.
|
|
15
|
-
*
|
|
16
|
-
* **Model.** `DecisionParams.Model`, the model-vendor row's `APIName`, defaulting to
|
|
17
|
-
* `pplx-decider-v1-27b`, the only model the API serves.
|
|
4
|
+
* which serves `pplx-decider-v1-27b`, its only model. The API takes the key only as a bearer token (not
|
|
5
|
+
* `x-api-key`), and answers `404` to a path with a trailing slash. The endpoint, key and error handling
|
|
6
|
+
* come from {@link BaseHostedSystemOneDecision}.
|
|
18
7
|
*/
|
|
19
|
-
export declare class PerplexityDecision extends
|
|
8
|
+
export declare class PerplexityDecision extends BaseHostedSystemOneDecision {
|
|
20
9
|
/** The Perplexity Decisions API endpoint. */
|
|
21
10
|
static readonly DEFAULT_ENDPOINT = "https://api.perplexity.ai/v1/decisions";
|
|
22
11
|
/** The model used when DecisionParams.Model is empty. */
|
|
23
12
|
static readonly DEFAULT_MODEL = "pplx-decider-v1-27b";
|
|
24
|
-
private _endpointURL;
|
|
25
|
-
/**
|
|
26
|
-
* @param apiKey A Perplexity API key, or an AI Credential's values in JSON.
|
|
27
|
-
* @param endpointURL Overrides the credential's `endpoint` and the default endpoint.
|
|
28
|
-
*/
|
|
29
|
-
constructor(apiKey: string, endpointURL?: string);
|
|
30
|
-
/** The configured Decisions API endpoint URL. */
|
|
31
|
-
get EndpointURL(): string;
|
|
32
13
|
protected get ServiceName(): string;
|
|
33
14
|
protected get DefaultModel(): string;
|
|
34
|
-
|
|
35
|
-
protected
|
|
36
|
-
|
|
37
|
-
* Names Perplexity's `error.message` when the body has one. A `404` or `405` has an empty body and a
|
|
38
|
-
* `504` can be an HTML page, so those keep the default: the status and the start of the body.
|
|
39
|
-
*/
|
|
40
|
-
protected DescribeHTTPError(status: number, bodyText: string): string;
|
|
41
|
-
/**
|
|
42
|
-
* No API key stops the call before any request. It is a `NoCredentials` error that allows failover,
|
|
43
|
-
* as for the other System One drivers: another candidate may be configured.
|
|
44
|
-
*/
|
|
45
|
-
protected GetConfigurationError(): SystemOneConfigurationError | undefined;
|
|
15
|
+
protected get DefaultEndpoint(): string;
|
|
16
|
+
protected get APIKeyDescription(): string;
|
|
17
|
+
protected get LegacyKeyVariable(): string;
|
|
46
18
|
}
|
|
47
19
|
//# sourceMappingURL=perplexityDecision.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perplexityDecision.d.ts","sourceRoot":"","sources":["../../src/models/perplexityDecision.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"perplexityDecision.d.ts","sourceRoot":"","sources":["../../src/models/perplexityDecision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AAG/E;;;;;GAKG;AACH,qBACa,kBAAmB,SAAQ,2BAA2B;IAC/D,6CAA6C;IAC7C,gBAAuB,gBAAgB,4CAA4C;IAEnF,yDAAyD;IACzD,gBAAuB,aAAa,yBAAyB;IAE7D,SAAS,KAAK,WAAW,IAAI,MAAM,CAElC;IAED,SAAS,KAAK,YAAY,IAAI,MAAM,CAEnC;IAED,SAAS,KAAK,eAAe,IAAI,MAAM,CAEtC;IAED,SAAS,KAAK,iBAAiB,IAAI,MAAM,CAExC;IAED,SAAS,KAAK,iBAAiB,IAAI,MAAM,CAExC;CACJ"}
|
|
@@ -4,91 +4,39 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
-
};
|
|
10
7
|
var PerplexityDecision_1;
|
|
11
|
-
import { BaseDecision,
|
|
12
|
-
import { RegisterClass
|
|
8
|
+
import { BaseDecision, BaseHostedSystemOneDecision } from '@memberjunction/ai';
|
|
9
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
13
10
|
/**
|
|
14
11
|
* A `BaseDecision` driver for Perplexity's Decisions API, `POST https://api.perplexity.ai/v1/decisions`,
|
|
15
|
-
* which serves
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* error messages.
|
|
19
|
-
*
|
|
20
|
-
* **Key.** A Perplexity API key, sent as `Authorization: Bearer <key>` (the API does not read
|
|
21
|
-
* `x-api-key`). A raw key or an `API Key` AI Credential's values in JSON (`{"apiKey":"…"}`).
|
|
22
|
-
*
|
|
23
|
-
* **Endpoint.** The constructor's URL, else the credential's `endpoint` (an `API Key with Endpoint`
|
|
24
|
-
* credential), else {@link PerplexityDecision.DEFAULT_ENDPOINT}. Each is the full request URL, unlike
|
|
25
|
-
* `SystemOneDecision`'s base URL. Trailing slashes are removed: the API answers `404` to a path with one.
|
|
26
|
-
*
|
|
27
|
-
* **Model.** `DecisionParams.Model`, the model-vendor row's `APIName`, defaulting to
|
|
28
|
-
* `pplx-decider-v1-27b`, the only model the API serves.
|
|
12
|
+
* which serves `pplx-decider-v1-27b`, its only model. The API takes the key only as a bearer token (not
|
|
13
|
+
* `x-api-key`), and answers `404` to a path with a trailing slash. The endpoint, key and error handling
|
|
14
|
+
* come from {@link BaseHostedSystemOneDecision}.
|
|
29
15
|
*/
|
|
30
|
-
let PerplexityDecision = class PerplexityDecision extends
|
|
16
|
+
let PerplexityDecision = class PerplexityDecision extends BaseHostedSystemOneDecision {
|
|
31
17
|
static { PerplexityDecision_1 = this; }
|
|
32
18
|
/** The Perplexity Decisions API endpoint. */
|
|
33
19
|
static { this.DEFAULT_ENDPOINT = 'https://api.perplexity.ai/v1/decisions'; }
|
|
34
20
|
/** The model used when DecisionParams.Model is empty. */
|
|
35
21
|
static { this.DEFAULT_MODEL = 'pplx-decider-v1-27b'; }
|
|
36
|
-
/**
|
|
37
|
-
* @param apiKey A Perplexity API key, or an AI Credential's values in JSON.
|
|
38
|
-
* @param endpointURL Overrides the credential's `endpoint` and the default endpoint.
|
|
39
|
-
*/
|
|
40
|
-
constructor(apiKey, endpointURL) {
|
|
41
|
-
super(apiKey);
|
|
42
|
-
const endpoint = NonEmptyString(endpointURL) ?? this.Credential.Endpoint ?? PerplexityDecision_1.DEFAULT_ENDPOINT;
|
|
43
|
-
this._endpointURL = TrimTrailingSlashes(endpoint);
|
|
44
|
-
}
|
|
45
|
-
/** The configured Decisions API endpoint URL. */
|
|
46
|
-
get EndpointURL() {
|
|
47
|
-
return this._endpointURL;
|
|
48
|
-
}
|
|
49
22
|
get ServiceName() {
|
|
50
23
|
return 'Perplexity Decisions API';
|
|
51
24
|
}
|
|
52
25
|
get DefaultModel() {
|
|
53
26
|
return PerplexityDecision_1.DEFAULT_MODEL;
|
|
54
27
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return this.EndpointURL;
|
|
28
|
+
get DefaultEndpoint() {
|
|
29
|
+
return PerplexityDecision_1.DEFAULT_ENDPOINT;
|
|
58
30
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
* `504` can be an HTML page, so those keep the default: the status and the start of the body.
|
|
62
|
-
*/
|
|
63
|
-
DescribeHTTPError(status, bodyText) {
|
|
64
|
-
const message = perplexityErrorMessage(SafeJSONParse(bodyText));
|
|
65
|
-
return message ? `${this.ServiceName} returned HTTP ${status}: ${message}` : super.DescribeHTTPError(status, bodyText);
|
|
31
|
+
get APIKeyDescription() {
|
|
32
|
+
return 'a Perplexity API key';
|
|
66
33
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
* as for the other System One drivers: another candidate may be configured.
|
|
70
|
-
*/
|
|
71
|
-
GetConfigurationError() {
|
|
72
|
-
if (this.Credential.APIKey.trim().length > 0) {
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
return {
|
|
76
|
-
ErrorType: 'NoCredentials',
|
|
77
|
-
Message: `${this.ServiceName} has no API key: bind an 'API Key' credential whose apiKey is a Perplexity API key, or set AI_VENDOR_API_KEY__PERPLEXITYDECISION`,
|
|
78
|
-
};
|
|
34
|
+
get LegacyKeyVariable() {
|
|
35
|
+
return 'AI_VENDOR_API_KEY__PERPLEXITYDECISION';
|
|
79
36
|
}
|
|
80
37
|
};
|
|
81
38
|
PerplexityDecision = PerplexityDecision_1 = __decorate([
|
|
82
|
-
RegisterClass(BaseDecision, 'PerplexityDecision')
|
|
83
|
-
__metadata("design:paramtypes", [String, String])
|
|
39
|
+
RegisterClass(BaseDecision, 'PerplexityDecision')
|
|
84
40
|
], PerplexityDecision);
|
|
85
41
|
export { PerplexityDecision };
|
|
86
|
-
/** The `error.message` of a Perplexity error body (`{ error: { message, type, code } }`), or an empty string. */
|
|
87
|
-
function perplexityErrorMessage(body) {
|
|
88
|
-
if (!IsSystemOneWireObject(body)) {
|
|
89
|
-
return '';
|
|
90
|
-
}
|
|
91
|
-
const error = body['error'];
|
|
92
|
-
return IsSystemOneWireObject(error) && typeof error['message'] === 'string' ? error['message'].trim() : '';
|
|
93
|
-
}
|
|
94
42
|
//# sourceMappingURL=perplexityDecision.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perplexityDecision.js","sourceRoot":"","sources":["../../src/models/perplexityDecision.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"perplexityDecision.js","sourceRoot":"","sources":["../../src/models/perplexityDecision.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD;;;;;GAKG;AAEI,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,2BAA2B;;IAC/D,6CAA6C;aACtB,qBAAgB,GAAG,wCAAwC,AAA3C,CAA4C;IAEnF,yDAAyD;aAClC,kBAAa,GAAG,qBAAqB,AAAxB,CAAyB;IAE7D,IAAc,WAAW;QACrB,OAAO,0BAA0B,CAAC;IACtC,CAAC;IAED,IAAc,YAAY;QACtB,OAAO,oBAAkB,CAAC,aAAa,CAAC;IAC5C,CAAC;IAED,IAAc,eAAe;QACzB,OAAO,oBAAkB,CAAC,gBAAgB,CAAC;IAC/C,CAAC;IAED,IAAc,iBAAiB;QAC3B,OAAO,sBAAsB,CAAC;IAClC,CAAC;IAED,IAAc,iBAAiB;QAC3B,OAAO,uCAAuC,CAAC;IACnD,CAAC;;AAzBQ,kBAAkB;IAD9B,aAAa,CAAC,YAAY,EAAE,oBAAoB,CAAC;GACrC,kBAAkB,CA0B9B"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AIErrorType, BaseHostedSystemOneDecision } from '@memberjunction/ai';
|
|
2
|
+
/**
|
|
3
|
+
* A `BaseDecision` driver for Subquadratic's SubQ Decisions API, `POST https://api.subq.ai/v1/systemone`,
|
|
4
|
+
* which serves SubQ Snap (`subq-snap-preview`, in public preview; the ID changes at general availability,
|
|
5
|
+
* so the model-vendor row's `APIName` is where to change it). Errors arrive as `{ detail: { error_type,
|
|
6
|
+
* message } }`. The endpoint, key and error handling come from {@link BaseHostedSystemOneDecision}.
|
|
7
|
+
*
|
|
8
|
+
* Not sent: the API's optional `images` (up to 4), which `DecisionParams` has no field for.
|
|
9
|
+
*/
|
|
10
|
+
export declare class SubQDecision extends BaseHostedSystemOneDecision {
|
|
11
|
+
/** The SubQ Decisions API endpoint. */
|
|
12
|
+
static readonly DEFAULT_ENDPOINT = "https://api.subq.ai/v1/systemone";
|
|
13
|
+
/** The model used when DecisionParams.Model is empty. */
|
|
14
|
+
static readonly DEFAULT_MODEL = "subq-snap-preview";
|
|
15
|
+
protected get ServiceName(): string;
|
|
16
|
+
protected get DefaultModel(): string;
|
|
17
|
+
protected get DefaultEndpoint(): string;
|
|
18
|
+
protected get APIKeyDescription(): string;
|
|
19
|
+
protected get LegacyKeyVariable(): string;
|
|
20
|
+
/**
|
|
21
|
+
* Pins three statuses whose `ErrorAnalyzer` reading would depend on SubQ's message text, which SubQ
|
|
22
|
+
* documents only for `validation_error`. A `422` whose message names no validation word reads as a
|
|
23
|
+
* fatal `InvalidRequest`, and a `403` whose message says "unauthorized" as a fatal `Authentication`
|
|
24
|
+
* error: either stops `Default Decision`'s failover loop, though another candidate could answer.
|
|
25
|
+
* - `402` (no credits) is `NoCredit`;
|
|
26
|
+
* - `403` (the key cannot use the model) and `422` (a request SubQ rejects, which passed MJ's own
|
|
27
|
+
* validation) are `ModelError`: another model may answer.
|
|
28
|
+
*
|
|
29
|
+
* Not `Authentication` or `VendorValidationError`: on those the runner drops the vendor's other
|
|
30
|
+
* candidates, and the index it continues from then skips the next candidate (`BaseModelRunner`).
|
|
31
|
+
*
|
|
32
|
+
* `ErrorAnalyzer` keeps the rest: `401` stays a fatal `Authentication` error, as for every other
|
|
33
|
+
* driver; `429` and `503` allow failover.
|
|
34
|
+
*/
|
|
35
|
+
protected GetHTTPErrorType(status: number): AIErrorType | undefined;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=subqDecision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subqDecision.d.ts","sourceRoot":"","sources":["../../src/models/subqDecision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AAG5F;;;;;;;GAOG;AACH,qBACa,YAAa,SAAQ,2BAA2B;IACzD,uCAAuC;IACvC,gBAAuB,gBAAgB,sCAAsC;IAE7E,yDAAyD;IACzD,gBAAuB,aAAa,uBAAuB;IAE3D,SAAS,KAAK,WAAW,IAAI,MAAM,CAElC;IAED,SAAS,KAAK,YAAY,IAAI,MAAM,CAEnC;IAED,SAAS,KAAK,eAAe,IAAI,MAAM,CAEtC;IAED,SAAS,KAAK,iBAAiB,IAAI,MAAM,CAExC;IAED,SAAS,KAAK,iBAAiB,IAAI,MAAM,CAExC;IAED;;;;;;;;;;;;;;OAcG;IACH,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;CAWtE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var SubQDecision_1;
|
|
8
|
+
import { BaseDecision, BaseHostedSystemOneDecision } from '@memberjunction/ai';
|
|
9
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
10
|
+
/**
|
|
11
|
+
* A `BaseDecision` driver for Subquadratic's SubQ Decisions API, `POST https://api.subq.ai/v1/systemone`,
|
|
12
|
+
* which serves SubQ Snap (`subq-snap-preview`, in public preview; the ID changes at general availability,
|
|
13
|
+
* so the model-vendor row's `APIName` is where to change it). Errors arrive as `{ detail: { error_type,
|
|
14
|
+
* message } }`. The endpoint, key and error handling come from {@link BaseHostedSystemOneDecision}.
|
|
15
|
+
*
|
|
16
|
+
* Not sent: the API's optional `images` (up to 4), which `DecisionParams` has no field for.
|
|
17
|
+
*/
|
|
18
|
+
let SubQDecision = class SubQDecision extends BaseHostedSystemOneDecision {
|
|
19
|
+
static { SubQDecision_1 = this; }
|
|
20
|
+
/** The SubQ Decisions API endpoint. */
|
|
21
|
+
static { this.DEFAULT_ENDPOINT = 'https://api.subq.ai/v1/systemone'; }
|
|
22
|
+
/** The model used when DecisionParams.Model is empty. */
|
|
23
|
+
static { this.DEFAULT_MODEL = 'subq-snap-preview'; }
|
|
24
|
+
get ServiceName() {
|
|
25
|
+
return 'SubQ Decisions API';
|
|
26
|
+
}
|
|
27
|
+
get DefaultModel() {
|
|
28
|
+
return SubQDecision_1.DEFAULT_MODEL;
|
|
29
|
+
}
|
|
30
|
+
get DefaultEndpoint() {
|
|
31
|
+
return SubQDecision_1.DEFAULT_ENDPOINT;
|
|
32
|
+
}
|
|
33
|
+
get APIKeyDescription() {
|
|
34
|
+
return 'a SubQ API key';
|
|
35
|
+
}
|
|
36
|
+
get LegacyKeyVariable() {
|
|
37
|
+
return 'AI_VENDOR_API_KEY__SUBQDECISION';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Pins three statuses whose `ErrorAnalyzer` reading would depend on SubQ's message text, which SubQ
|
|
41
|
+
* documents only for `validation_error`. A `422` whose message names no validation word reads as a
|
|
42
|
+
* fatal `InvalidRequest`, and a `403` whose message says "unauthorized" as a fatal `Authentication`
|
|
43
|
+
* error: either stops `Default Decision`'s failover loop, though another candidate could answer.
|
|
44
|
+
* - `402` (no credits) is `NoCredit`;
|
|
45
|
+
* - `403` (the key cannot use the model) and `422` (a request SubQ rejects, which passed MJ's own
|
|
46
|
+
* validation) are `ModelError`: another model may answer.
|
|
47
|
+
*
|
|
48
|
+
* Not `Authentication` or `VendorValidationError`: on those the runner drops the vendor's other
|
|
49
|
+
* candidates, and the index it continues from then skips the next candidate (`BaseModelRunner`).
|
|
50
|
+
*
|
|
51
|
+
* `ErrorAnalyzer` keeps the rest: `401` stays a fatal `Authentication` error, as for every other
|
|
52
|
+
* driver; `429` and `503` allow failover.
|
|
53
|
+
*/
|
|
54
|
+
GetHTTPErrorType(status) {
|
|
55
|
+
switch (status) {
|
|
56
|
+
case 402:
|
|
57
|
+
return 'NoCredit';
|
|
58
|
+
case 403:
|
|
59
|
+
case 422:
|
|
60
|
+
return 'ModelError';
|
|
61
|
+
default:
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
SubQDecision = SubQDecision_1 = __decorate([
|
|
67
|
+
RegisterClass(BaseDecision, 'SubQDecision')
|
|
68
|
+
], SubQDecision);
|
|
69
|
+
export { SubQDecision };
|
|
70
|
+
//# sourceMappingURL=subqDecision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subqDecision.js","sourceRoot":"","sources":["../../src/models/subqDecision.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAe,YAAY,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD;;;;;;;GAOG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,2BAA2B;;IACzD,uCAAuC;aAChB,qBAAgB,GAAG,kCAAkC,AAArC,CAAsC;IAE7E,yDAAyD;aAClC,kBAAa,GAAG,mBAAmB,AAAtB,CAAuB;IAE3D,IAAc,WAAW;QACrB,OAAO,oBAAoB,CAAC;IAChC,CAAC;IAED,IAAc,YAAY;QACtB,OAAO,cAAY,CAAC,aAAa,CAAC;IACtC,CAAC;IAED,IAAc,eAAe;QACzB,OAAO,cAAY,CAAC,gBAAgB,CAAC;IACzC,CAAC;IAED,IAAc,iBAAiB;QAC3B,OAAO,gBAAgB,CAAC;IAC5B,CAAC;IAED,IAAc,iBAAiB;QAC3B,OAAO,iCAAiC,CAAC;IAC7C,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACO,gBAAgB,CAAC,MAAc;QACrC,QAAQ,MAAM,EAAE,CAAC;YACb,KAAK,GAAG;gBACJ,OAAO,UAAU,CAAC;YACtB,KAAK,GAAG,CAAC;YACT,KAAK,GAAG;gBACJ,OAAO,YAAY,CAAC;YACxB;gBACI,OAAO,SAAS,CAAC;QACzB,CAAC;IACL,CAAC;;AApDQ,YAAY;IADxB,aAAa,CAAC,YAAY,EAAE,cAAc,CAAC;GAC/B,YAAY,CAqDxB"}
|
|
@@ -8,8 +8,8 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
10
|
var SystemOneDecision_1;
|
|
11
|
-
import { BaseDecision, BaseSystemOneDecision,
|
|
12
|
-
import { RegisterClass
|
|
11
|
+
import { BaseDecision, BaseSystemOneDecision, NonEmptyString, ReadSystemOneErrorMessage, TrimTrailingSlashes, } from '@memberjunction/ai';
|
|
12
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
13
13
|
/** The route every System One server answers on. */
|
|
14
14
|
const SYSTEMONE_PATH = '/v1/systemone';
|
|
15
15
|
/**
|
|
@@ -77,7 +77,7 @@ let SystemOneDecision = class SystemOneDecision extends BaseSystemOneDecision {
|
|
|
77
77
|
* string or a list of `{ msg }`; llama.cpp sends `error.message`. Otherwise the start of the body.
|
|
78
78
|
*/
|
|
79
79
|
DescribeHTTPError(status, bodyText) {
|
|
80
|
-
const message =
|
|
80
|
+
const message = ReadSystemOneErrorMessage(bodyText);
|
|
81
81
|
return message ? `${this.ServiceName} returned HTTP ${status}: ${message}` : super.DescribeHTTPError(status, bodyText);
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
@@ -111,25 +111,4 @@ export function ToSystemOneURL(baseURL) {
|
|
|
111
111
|
}
|
|
112
112
|
return base.endsWith('/v1') ? `${base}/systemone` : `${base}${SYSTEMONE_PATH}`;
|
|
113
113
|
}
|
|
114
|
-
/** The error message a System One server put in its body, or an empty string. */
|
|
115
|
-
function serverMessage(body) {
|
|
116
|
-
if (!IsSystemOneWireObject(body)) {
|
|
117
|
-
return '';
|
|
118
|
-
}
|
|
119
|
-
const detail = body['detail'];
|
|
120
|
-
if (typeof detail === 'string') {
|
|
121
|
-
return detail.trim();
|
|
122
|
-
}
|
|
123
|
-
if (Array.isArray(detail)) {
|
|
124
|
-
return detail
|
|
125
|
-
.map(d => (IsSystemOneWireObject(d) && typeof d['msg'] === 'string' ? d['msg'].trim() : ''))
|
|
126
|
-
.filter(m => m.length > 0)
|
|
127
|
-
.join('; ');
|
|
128
|
-
}
|
|
129
|
-
const error = body['error'];
|
|
130
|
-
if (IsSystemOneWireObject(error) && typeof error['message'] === 'string') {
|
|
131
|
-
return error['message'].trim();
|
|
132
|
-
}
|
|
133
|
-
return typeof error === 'string' ? error.trim() : '';
|
|
134
|
-
}
|
|
135
114
|
//# sourceMappingURL=systemOneDecision.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"systemOneDecision.js","sourceRoot":"","sources":["../../src/models/systemOneDecision.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EACH,YAAY,EACZ,qBAAqB,EACrB,
|
|
1
|
+
{"version":3,"file":"systemOneDecision.js","sourceRoot":"","sources":["../../src/models/systemOneDecision.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ai-systemone",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "6.2.0-edge.
|
|
5
|
-
"description": "MemberJunction drivers for System One decision APIs: any server with POST /v1/systemone (Kev on Modal, llama.cpp llama-server, TypeSafe),
|
|
4
|
+
"version": "6.2.0-edge.6",
|
|
5
|
+
"description": "MemberJunction drivers for System One decision APIs: any server with POST /v1/systemone (Kev on Modal, llama.cpp llama-server, TypeSafe), Perplexity's Decisions API (pplx-decider-v1-27b) and Subquadratic's SubQ Decisions API (SubQ Snap)",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"files": [
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"typescript": "^5.9.3"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@memberjunction/ai": "6.2.0-edge.
|
|
19
|
-
"@memberjunction/global": "6.2.0-edge.
|
|
18
|
+
"@memberjunction/ai": "6.2.0-edge.6",
|
|
19
|
+
"@memberjunction/global": "6.2.0-edge.6"
|
|
20
20
|
},
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|