@maximem/synap-js-sdk 0.5.12 → 0.5.14
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/dist/index.cjs +65 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/index.js +55 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -949,6 +949,16 @@ interface WaitOptions {
|
|
|
949
949
|
signal?: AbortSignal;
|
|
950
950
|
}
|
|
951
951
|
|
|
952
|
+
/**
|
|
953
|
+
* Scope-aware context fetching.
|
|
954
|
+
*
|
|
955
|
+
* Scopes are client > customer > user. `conversation_id` is NOT a tier: it
|
|
956
|
+
* groups turns within a scope. Passing it narrows an existing scope rather
|
|
957
|
+
* than selecting a different one.
|
|
958
|
+
*/
|
|
959
|
+
|
|
960
|
+
type Scope = 'user' | 'customer' | 'client' | 'conversation';
|
|
961
|
+
|
|
952
962
|
/**
|
|
953
963
|
* Conversation namespace. Mirrors `ConversationInterface` and
|
|
954
964
|
* `ConversationContextInterface` in the Python SDK.
|
|
@@ -1106,16 +1116,6 @@ type WriteInvalidator = (ids: {
|
|
|
1106
1116
|
customerId?: string | undefined;
|
|
1107
1117
|
}) => void;
|
|
1108
1118
|
|
|
1109
|
-
/**
|
|
1110
|
-
* Scope-aware context fetching.
|
|
1111
|
-
*
|
|
1112
|
-
* Scopes are client > customer > user. `conversation_id` is NOT a tier: it
|
|
1113
|
-
* groups turns within a scope. Passing it narrows an existing scope rather
|
|
1114
|
-
* than selecting a different one.
|
|
1115
|
-
*/
|
|
1116
|
-
|
|
1117
|
-
type Scope = 'user' | 'customer' | 'client' | 'conversation';
|
|
1118
|
-
|
|
1119
1119
|
/** User namespace. Mirrors `UserInterface` in the Python SDK. */
|
|
1120
1120
|
|
|
1121
1121
|
interface UserNamespace {
|
|
@@ -1873,7 +1873,7 @@ declare class SynapClient {
|
|
|
1873
1873
|
* build when the two disagree, which is the only thing that makes a manual
|
|
1874
1874
|
* publish safe.
|
|
1875
1875
|
*/
|
|
1876
|
-
declare const SDK_VERSION = "0.5.
|
|
1876
|
+
declare const SDK_VERSION = "0.5.14";
|
|
1877
1877
|
|
|
1878
1878
|
/**
|
|
1879
1879
|
* `response_shape: "ranked"`: one list in the order the server ranked it.
|
package/dist/index.d.ts
CHANGED
|
@@ -949,6 +949,16 @@ interface WaitOptions {
|
|
|
949
949
|
signal?: AbortSignal;
|
|
950
950
|
}
|
|
951
951
|
|
|
952
|
+
/**
|
|
953
|
+
* Scope-aware context fetching.
|
|
954
|
+
*
|
|
955
|
+
* Scopes are client > customer > user. `conversation_id` is NOT a tier: it
|
|
956
|
+
* groups turns within a scope. Passing it narrows an existing scope rather
|
|
957
|
+
* than selecting a different one.
|
|
958
|
+
*/
|
|
959
|
+
|
|
960
|
+
type Scope = 'user' | 'customer' | 'client' | 'conversation';
|
|
961
|
+
|
|
952
962
|
/**
|
|
953
963
|
* Conversation namespace. Mirrors `ConversationInterface` and
|
|
954
964
|
* `ConversationContextInterface` in the Python SDK.
|
|
@@ -1106,16 +1116,6 @@ type WriteInvalidator = (ids: {
|
|
|
1106
1116
|
customerId?: string | undefined;
|
|
1107
1117
|
}) => void;
|
|
1108
1118
|
|
|
1109
|
-
/**
|
|
1110
|
-
* Scope-aware context fetching.
|
|
1111
|
-
*
|
|
1112
|
-
* Scopes are client > customer > user. `conversation_id` is NOT a tier: it
|
|
1113
|
-
* groups turns within a scope. Passing it narrows an existing scope rather
|
|
1114
|
-
* than selecting a different one.
|
|
1115
|
-
*/
|
|
1116
|
-
|
|
1117
|
-
type Scope = 'user' | 'customer' | 'client' | 'conversation';
|
|
1118
|
-
|
|
1119
1119
|
/** User namespace. Mirrors `UserInterface` in the Python SDK. */
|
|
1120
1120
|
|
|
1121
1121
|
interface UserNamespace {
|
|
@@ -1873,7 +1873,7 @@ declare class SynapClient {
|
|
|
1873
1873
|
* build when the two disagree, which is the only thing that makes a manual
|
|
1874
1874
|
* publish safe.
|
|
1875
1875
|
*/
|
|
1876
|
-
declare const SDK_VERSION = "0.5.
|
|
1876
|
+
declare const SDK_VERSION = "0.5.14";
|
|
1877
1877
|
|
|
1878
1878
|
/**
|
|
1879
1879
|
* `response_shape: "ranked"`: one list in the order the server ranked it.
|
package/dist/index.js
CHANGED
|
@@ -408,13 +408,25 @@ function isOutcomeUnknown(error) {
|
|
|
408
408
|
if (error instanceof ConflictError) return false;
|
|
409
409
|
if (error instanceof InsufficientCreditsError) return false;
|
|
410
410
|
if (error instanceof ContextNotFoundError) return false;
|
|
411
|
-
if (error instanceof NetworkTimeoutError) return true;
|
|
412
411
|
if (isConnectionRefusal(error)) return false;
|
|
412
|
+
if (error instanceof NetworkTimeoutError) return true;
|
|
413
413
|
return true;
|
|
414
414
|
}
|
|
415
|
+
var CONNECTION_REFUSAL_CODES = /* @__PURE__ */ new Set([
|
|
416
|
+
"ECONNREFUSED",
|
|
417
|
+
"ENOTFOUND",
|
|
418
|
+
"EAI_AGAIN",
|
|
419
|
+
"ECONNRESET",
|
|
420
|
+
"EHOSTUNREACH"
|
|
421
|
+
]);
|
|
415
422
|
function isConnectionRefusal(error) {
|
|
416
|
-
|
|
417
|
-
|
|
423
|
+
let cur = error;
|
|
424
|
+
for (let depth = 0; depth < 4 && cur !== null && typeof cur === "object"; depth += 1) {
|
|
425
|
+
const code = cur.code;
|
|
426
|
+
if (typeof code === "string" && CONNECTION_REFUSAL_CODES.has(code)) return true;
|
|
427
|
+
cur = cur.cause;
|
|
428
|
+
}
|
|
429
|
+
return false;
|
|
418
430
|
}
|
|
419
431
|
function toTransportError(error, correlationId) {
|
|
420
432
|
if (error instanceof SynapError) return error;
|
|
@@ -422,6 +434,12 @@ function toTransportError(error, correlationId) {
|
|
|
422
434
|
if (name === "AbortError" || name === "TimeoutError") {
|
|
423
435
|
return new NetworkTimeoutError("Request timed out", { correlationId, cause: error });
|
|
424
436
|
}
|
|
437
|
+
if (isConnectionRefusal(error)) {
|
|
438
|
+
return new NetworkTimeoutError(
|
|
439
|
+
`Connection failed: ${error?.message ?? String(error)}`,
|
|
440
|
+
{ correlationId, cause: error }
|
|
441
|
+
);
|
|
442
|
+
}
|
|
425
443
|
return new ServiceUnavailableError(
|
|
426
444
|
`Network request failed: ${error?.message ?? String(error)}`,
|
|
427
445
|
{ correlationId, cause: error }
|
|
@@ -493,6 +511,7 @@ async function toHttpError(response, correlationId) {
|
|
|
493
511
|
return new AgentUnavailableError(message, opts);
|
|
494
512
|
default:
|
|
495
513
|
if (response.status >= 500) return new ServiceUnavailableError(message, opts);
|
|
514
|
+
if (response.status >= 400) return new SynapPermanentError(message, opts);
|
|
496
515
|
return new SynapError(message, opts);
|
|
497
516
|
}
|
|
498
517
|
}
|
|
@@ -758,8 +777,13 @@ async function fetchContext(transport, scope, options = {}, hooks = {}) {
|
|
|
758
777
|
hooks.onResponse?.(scope, options, response2);
|
|
759
778
|
return response2;
|
|
760
779
|
};
|
|
780
|
+
const conversationId = opt(options, "conversation_id", "conversationId");
|
|
781
|
+
const skipServerSt = conversationId ? hooks.skipServerShortTerm?.(conversationId) === true : false;
|
|
761
782
|
const network = async () => {
|
|
762
|
-
const { endpoint, body } = buildFetchRequest(
|
|
783
|
+
const { endpoint, body } = buildFetchRequest(
|
|
784
|
+
scope,
|
|
785
|
+
skipServerSt ? { ...options, include_conversation_context: false } : options
|
|
786
|
+
);
|
|
763
787
|
const result = await transport.request(endpoint, { body });
|
|
764
788
|
return applyResponseShape(result?.["context"] ?? {}, responseShape);
|
|
765
789
|
};
|
|
@@ -1417,10 +1441,11 @@ function storedBatchRows(bodies, result) {
|
|
|
1417
1441
|
});
|
|
1418
1442
|
return pairs;
|
|
1419
1443
|
}
|
|
1444
|
+
var PROMPT_STYLES = ["structured", "narrative", "bullet_points"];
|
|
1420
1445
|
function createConversationNamespace(transport, subscribers = new CompactionSubscribers(), onWrite = () => {
|
|
1421
1446
|
}, onTurn = () => {
|
|
1422
1447
|
}, onFetched = () => {
|
|
1423
|
-
}, localShortTerm = { prompt: () => null, compacted: () => null }, agentModel = () => ({})) {
|
|
1448
|
+
}, localShortTerm = { prompt: () => null, compacted: () => null }, agentModel = () => ({}), fetchHooks = {}) {
|
|
1424
1449
|
const writesInFlight = /* @__PURE__ */ new Map();
|
|
1425
1450
|
const withTurnModel = (body, options) => {
|
|
1426
1451
|
const metadata = withAgentModel(
|
|
@@ -1527,7 +1552,7 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
|
|
|
1527
1552
|
async fetch(options = {}) {
|
|
1528
1553
|
const id = options.conversation_id ?? options.conversationId;
|
|
1529
1554
|
validateConversationId(id);
|
|
1530
|
-
const response = await fetchContext(transport, "conversation", options);
|
|
1555
|
+
const response = await fetchContext(transport, "conversation", options, fetchHooks);
|
|
1531
1556
|
onFetched(
|
|
1532
1557
|
response,
|
|
1533
1558
|
id,
|
|
@@ -1538,6 +1563,12 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
|
|
|
1538
1563
|
},
|
|
1539
1564
|
get_context_for_prompt: async (options = {}) => {
|
|
1540
1565
|
const id = convId(options);
|
|
1566
|
+
const style = options.style ?? "structured";
|
|
1567
|
+
if (!PROMPT_STYLES.includes(style)) {
|
|
1568
|
+
throw new InvalidInputError(
|
|
1569
|
+
`Invalid style '${style}'. Must be one of: ${PROMPT_STYLES.join(", ")}`
|
|
1570
|
+
);
|
|
1571
|
+
}
|
|
1541
1572
|
const search = (options.search_history ?? options.searchHistory ?? true) && localShortTerm.historyExcerpts;
|
|
1542
1573
|
const withHistory = async (response2) => {
|
|
1543
1574
|
if (!search) return response2;
|
|
@@ -1547,11 +1578,11 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
|
|
|
1547
1578
|
return response2;
|
|
1548
1579
|
}
|
|
1549
1580
|
};
|
|
1550
|
-
const local = localShortTerm.prompt(id,
|
|
1581
|
+
const local = localShortTerm.prompt(id, style);
|
|
1551
1582
|
if (local !== null) return withHistory(local);
|
|
1552
1583
|
const result = await transport.request("context_for_prompt", {
|
|
1553
1584
|
pathParams: { conversation_id: id },
|
|
1554
|
-
query: { style
|
|
1585
|
+
query: { style }
|
|
1555
1586
|
});
|
|
1556
1587
|
const response = result?.["context_for_prompt"] ?? result ?? {};
|
|
1557
1588
|
localShortTerm.reseed?.(id, response);
|
|
@@ -1976,7 +2007,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
|
|
|
1976
2007
|
}
|
|
1977
2008
|
|
|
1978
2009
|
// src/version.ts
|
|
1979
|
-
var SDK_VERSION = "0.5.
|
|
2010
|
+
var SDK_VERSION = "0.5.14";
|
|
1980
2011
|
|
|
1981
2012
|
// src/registry.ts
|
|
1982
2013
|
var instances = /* @__PURE__ */ new Map();
|
|
@@ -3799,6 +3830,14 @@ var SynapClient = class _SynapClient {
|
|
|
3799
3830
|
// user, customer and client fetches (the conversation fetch does its own
|
|
3800
3831
|
// through `onFetched`). Until 0.5.12 only the conversation fetch had it,
|
|
3801
3832
|
// so the same usage gave the model different context in JS.
|
|
3833
|
+
// Python's `_should_skip_server_st`: when this process already holds the
|
|
3834
|
+
// conversation's compaction and every turn after it, the server is told
|
|
3835
|
+
// not to assemble them again.
|
|
3836
|
+
skipServerShortTerm: (conversationId) => {
|
|
3837
|
+
if (!this.#isStAuthoritative()) return false;
|
|
3838
|
+
const entry = this.#shortTerm.get(conversationId);
|
|
3839
|
+
return entry !== null && entry.compactionId !== null && isComplete(entry);
|
|
3840
|
+
},
|
|
3802
3841
|
onResponse: (scope, options2, response) => {
|
|
3803
3842
|
if (scope === "conversation") return;
|
|
3804
3843
|
const o2 = options2;
|
|
@@ -3862,7 +3901,12 @@ var SynapClient = class _SynapClient {
|
|
|
3862
3901
|
reseed: (conversationId, response) => this.#reseedShortTerm(conversationId, response),
|
|
3863
3902
|
historyExcerpts: (conversationId, response, query) => this.#withHistoryExcerpts(conversationId, response, query)
|
|
3864
3903
|
},
|
|
3865
|
-
() => this.#agentModel
|
|
3904
|
+
() => this.#agentModel,
|
|
3905
|
+
// The same hooks as the other three scopes: the anticipation cache first,
|
|
3906
|
+
// as Python's conversation fetch does, and the audit events. Until 0.5.13
|
|
3907
|
+
// the conversation fetch was built without them, so every JS conversation
|
|
3908
|
+
// fetch was a billed round trip, including ones the stream had answered.
|
|
3909
|
+
this.#fetchHooks
|
|
3866
3910
|
);
|
|
3867
3911
|
this.memories = createMemoriesInterface(this.#transport, ({ userId, customerId }) => {
|
|
3868
3912
|
for (const id of /* @__PURE__ */ new Set([userId, customerId])) {
|
|
@@ -4476,7 +4520,7 @@ function resolveBaseUrl(options) {
|
|
|
4476
4520
|
function resolveCredentials(options) {
|
|
4477
4521
|
const apiKey = options.apiKey ?? getEnv("SYNAP_API_KEY");
|
|
4478
4522
|
if (!apiKey) {
|
|
4479
|
-
throw new
|
|
4523
|
+
throw new AuthenticationError(
|
|
4480
4524
|
"No Synap API key found. Set SYNAP_API_KEY in your environment, or pass apiKey to the SynapClient constructor."
|
|
4481
4525
|
);
|
|
4482
4526
|
}
|