querysub 0.443.0 → 0.446.0

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.
@@ -1,3 +1,130 @@
1
+ export type OpenRouterEffort = "none" | "low" | "medium" | "high";
2
+
3
+ export type OpenRouterResult = {
4
+ text: string;
5
+ /** Total cost of the call in USD, if OpenRouter reported it. */
6
+ cost: number | undefined;
7
+ };
8
+
9
+ /** Calls OpenRouter with an explicit model and reasoning effort.
10
+ * If `onProgress` is provided, the response is streamed and `onProgress` is
11
+ * called repeatedly with the accumulated text so far. The final full text
12
+ * (and cost) is returned regardless. */
13
+ export async function callOpenRouterModel(config: {
14
+ apiKey: string;
15
+ model: string;
16
+ prompt: string;
17
+ /** OpenRouter reasoning effort. "none" disables reasoning entirely. */
18
+ effort?: OpenRouterEffort;
19
+ /** Called with the accumulated text each time more is streamed in. */
20
+ onProgress?: (partial: string) => void;
21
+ }): Promise<OpenRouterResult> {
22
+ let body: Record<string, unknown> = {
23
+ model: config.model,
24
+ messages: [
25
+ {
26
+ role: "user",
27
+ content: config.prompt,
28
+ },
29
+ ],
30
+ // Ask OpenRouter to include usage (and therefore cost) in the response.
31
+ usage: { include: true },
32
+ };
33
+ if (config.effort === "none") {
34
+ body.reasoning = { enabled: false };
35
+ } else if (config.effort) {
36
+ body.reasoning = { effort: config.effort };
37
+ }
38
+
39
+ let streaming = !!config.onProgress;
40
+ if (streaming) {
41
+ body.stream = true;
42
+ }
43
+
44
+ const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
45
+ method: "POST",
46
+ headers: {
47
+ "Authorization": `Bearer ${config.apiKey}`,
48
+ "Content-Type": "application/json",
49
+ },
50
+ body: JSON.stringify(body),
51
+ });
52
+
53
+ if (!response.ok) {
54
+ const errorText = await response.text();
55
+ throw new Error(`OpenRouter API error: ${response.status} ${response.statusText} - ${errorText}`);
56
+ }
57
+
58
+ if (!streaming) {
59
+ const data = await response.json();
60
+
61
+ if (!data.choices || !data.choices[0] || !data.choices[0].message || !data.choices[0].message.content) {
62
+ throw new Error(`Unexpected OpenRouter API response format: ${JSON.stringify(data)}`);
63
+ }
64
+
65
+ let cost = typeof data.usage?.cost === "number" ? data.usage.cost as number : undefined;
66
+ return {
67
+ text: String(data.choices[0].message.content).trim(),
68
+ cost,
69
+ };
70
+ }
71
+
72
+ let reader = response.body?.getReader();
73
+ if (!reader) {
74
+ throw new Error(`OpenRouter streaming response had no body`);
75
+ }
76
+ let decoder = new TextDecoder();
77
+ let pending = "";
78
+ let full = "";
79
+ let cost: number | undefined;
80
+
81
+ function onLine(line: string) {
82
+ line = line.trim();
83
+ if (!line.startsWith("data: ")) return;
84
+ if (line === "data: [DONE]") return;
85
+ let data = JSON.parse(line.slice("data: ".length));
86
+ if (data?.error) {
87
+ throw new Error(`OpenRouter mid-stream error: ${JSON.stringify(data.error)}`);
88
+ }
89
+ if (typeof data?.usage?.cost === "number") {
90
+ cost = data.usage.cost;
91
+ }
92
+ let delta = data?.choices?.[0]?.delta?.content;
93
+ if (typeof delta === "string" && delta) {
94
+ full += delta;
95
+ config.onProgress?.(full);
96
+ }
97
+ }
98
+
99
+ while (true) {
100
+ let { done, value } = await reader.read();
101
+ if (done) break;
102
+ pending += decoder.decode(value, { stream: true });
103
+ let lines = pending.split("\n");
104
+ for (let i = 0; i < lines.length - 1; i++) {
105
+ try {
106
+ onLine(lines[i]);
107
+ } catch (e) {
108
+ // OpenRouter mixes the occasional non-JSON keep-alive comment into the stream.
109
+ if (!String(e).includes("SyntaxError")) throw e;
110
+ }
111
+ }
112
+ pending = lines[lines.length - 1];
113
+ }
114
+ if (pending.trim()) {
115
+ try {
116
+ onLine(pending);
117
+ } catch (e) {
118
+ if (!String(e).includes("SyntaxError")) throw e;
119
+ }
120
+ }
121
+
122
+ return {
123
+ text: full.trim(),
124
+ cost,
125
+ };
126
+ }
127
+
1
128
  export async function callOpenRouter(apiKey: string, prompt: string): Promise<string> {
2
129
  const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
3
130
  method: "POST",
@@ -278,6 +278,7 @@ async function auditAuthority(nodeId: string, pathsToAudit: { path: string }[],
278
278
  for (let pathObj of pathsToAudit) {
279
279
  let path = pathObj.path;
280
280
  let ourLatest = authorityStorage.getValueAtTime(path);
281
+ if (ourLatest?.event) continue;
281
282
  originalValues.set(path, ourLatest);
282
283
 
283
284
  // Ask for their latest valid (time: undefined means latest)
@@ -310,6 +311,8 @@ async function auditAuthority(nodeId: string, pathsToAudit: { path: string }[],
310
311
  let originalValue = originalValues.get(response.path);
311
312
  let ourValue = authorityStorage.getValueAtTime(response.path) || createMissingEpochValue(response.path);
312
313
 
314
+ if (ourValue.event || response.event) continue;
315
+
313
316
  let localValueChanged = false;
314
317
  if (originalValue === undefined && ourValue.time !== epochTime) {
315
318
  localValueChanged = true;
@@ -439,6 +442,7 @@ type ValidStateResponse = {
439
442
  time?: { time: number; version: number; creatorId: number };
440
443
  valid: boolean | undefined;
441
444
  isTransparent: boolean;
445
+ event: boolean;
442
446
  };
443
447
 
444
448
  class PathAuditerService {
@@ -451,6 +455,7 @@ class PathAuditerService {
451
455
  time: value?.time,
452
456
  valid: value === undefined ? undefined : value.valid,
453
457
  isTransparent: !!value?.isTransparent,
458
+ event: !!value?.event,
454
459
  });
455
460
  }
456
461
  return results;
package/test.ts CHANGED
@@ -3,7 +3,7 @@ chdir("D:/repos/qs-cyoa/");
3
3
 
4
4
  import "./inject";
5
5
  import { SocketFunction } from "socket-function/SocketFunction";
6
- import { getControllerNodeIdList } from "./src/-g-core-values/NodeCapabilities";
6
+ import { NodeCapabilitiesController, getControllerNodeIdList } from "./src/-g-core-values/NodeCapabilities";
7
7
  import { delay } from "socket-function/src/batching";
8
8
  import { green, yellow } from "socket-function/src/formatting/logColors";
9
9
  import { Querysub, t } from "./src/4-querysub/Querysub";
@@ -19,6 +19,9 @@ import { shutdown } from "./src/diagnostics/periodic";
19
19
  import { getShardPrefixes } from "./src/0-path-value-core/ShardPrefixes";
20
20
  import { PathValue, epochTime } from "./src/0-path-value-core/pathValueCore";
21
21
  import { pathValueSerializer } from "./src/-h-path-value-serialize/PathValueSerializer";
22
+ import { getAllNodeIds } from "./src/-f-node-discovery/NodeDiscovery";
23
+ import { errorToUndefinedSilent } from "./src/errors";
24
+ import { timeoutToUndefinedSilent } from "socket-function/src/misc";
22
25
 
23
26
  let tempTestSchema = Querysub.createSchema({
24
27
  value: t.number,
@@ -30,13 +33,19 @@ let tempTestSchema = Querysub.createSchema({
30
33
  });
31
34
 
32
35
  async function main() {
33
- // await Querysub.hostService("test");
36
+ await Querysub.hostService("test");
34
37
 
35
38
  // let testValues: PathValue[] = [];
36
39
  // let buffers = await pathValueSerializer.serialize(testValues);
37
40
  // let values = await pathValueSerializer.deserialize(buffers);
38
41
 
39
- let values = await pathValueArchives.loadValues(await getAllAuthoritySpec());
42
+ //let values = await pathValueArchives.loadValues(await getAllAuthoritySpec());
43
+
44
+ let nodes = await getAllNodeIds();
45
+ let values = await Promise.all(nodes.map(async node => {
46
+ return timeoutToUndefinedSilent(5000, NodeCapabilitiesController.nodes[node].getEntryPoint());
47
+ }));
48
+ console.log({ values });
40
49
 
41
50
  // let path = getProxyPath(() => tempTestSchema.data().value);
42
51
  // console.log({ path });