@fragno-dev/pi-fragment 0.0.1 → 0.0.3
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 +39 -3
- package/dist/browser/client/react.d.ts +44 -36
- package/dist/browser/client/react.d.ts.map +1 -1
- package/dist/browser/client/react.js +105 -22
- package/dist/browser/client/react.js.map +1 -1
- package/dist/browser/client/solid.d.ts +42 -36
- package/dist/browser/client/solid.d.ts.map +1 -1
- package/dist/browser/client/solid.js +27 -13
- package/dist/browser/client/solid.js.map +1 -1
- package/dist/browser/client/svelte.d.ts +42 -36
- package/dist/browser/client/svelte.d.ts.map +1 -1
- package/dist/browser/client/svelte.js +14 -6
- package/dist/browser/client/svelte.js.map +1 -1
- package/dist/browser/client/vanilla.d.ts +99 -39
- package/dist/browser/client/vanilla.d.ts.map +1 -1
- package/dist/browser/client/vanilla.js +151 -3
- package/dist/browser/client/vanilla.js.map +1 -1
- package/dist/browser/client/vue.d.ts +54 -38
- package/dist/browser/client/vue.d.ts.map +1 -1
- package/dist/browser/client/vue.js +25 -17
- package/dist/browser/client/vue.js.map +1 -1
- package/dist/browser/{factory-DKoO_lRA.js → clients-BscY_HVe.js} +1051 -799
- package/dist/browser/clients-BscY_HVe.js.map +1 -0
- package/dist/browser/index.d.ts +3 -776
- package/dist/browser/index.js +801 -2
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/routes-CpL_YGWK.d.ts +1560 -0
- package/dist/browser/routes-CpL_YGWK.d.ts.map +1 -0
- package/dist/cli/mod.d.ts.map +1 -1
- package/dist/cli/mod.js +245 -7
- package/dist/cli/mod.js.map +1 -1
- package/dist/node/{pi → client}/clients.d.ts +46 -36
- package/dist/node/client/clients.d.ts.map +1 -0
- package/dist/node/client/clients.js +54 -0
- package/dist/node/client/clients.js.map +1 -0
- package/dist/node/client/session-controller.d.ts +31 -0
- package/dist/node/client/session-controller.d.ts.map +1 -0
- package/dist/node/client/session-controller.js +33 -0
- package/dist/node/client/session-controller.js.map +1 -0
- package/dist/node/client/session-store.d.ts +71 -0
- package/dist/node/client/session-store.d.ts.map +1 -0
- package/dist/node/client/session-store.js +637 -0
- package/dist/node/client/session-store.js.map +1 -0
- package/dist/node/debug-log.d.ts +9 -0
- package/dist/node/debug-log.d.ts.map +1 -0
- package/dist/node/debug-log.js +58 -0
- package/dist/node/debug-log.js.map +1 -0
- package/dist/node/index.d.ts +5 -4
- package/dist/node/index.js +5 -3
- package/dist/node/pi/definition.d.ts +1 -1
- package/dist/node/pi/definition.d.ts.map +1 -1
- package/dist/node/pi/dsl.d.ts +5 -2
- package/dist/node/pi/dsl.d.ts.map +1 -1
- package/dist/node/pi/dsl.js +22 -3
- package/dist/node/pi/dsl.js.map +1 -1
- package/dist/node/pi/factory.d.ts +37 -34
- package/dist/node/pi/factory.d.ts.map +1 -1
- package/dist/node/pi/factory.js.map +1 -1
- package/dist/node/pi/mappers.js +0 -1
- package/dist/node/pi/mappers.js.map +1 -1
- package/dist/node/pi/route-schemas.js +42 -10
- package/dist/node/pi/route-schemas.js.map +1 -1
- package/dist/node/pi/types.d.ts +155 -7
- package/dist/node/pi/types.d.ts.map +1 -1
- package/dist/node/pi/types.js +6 -0
- package/dist/node/pi/types.js.map +1 -0
- package/dist/node/pi/workflow/active-session.d.ts +2 -0
- package/dist/node/pi/workflow/active-session.js +107 -0
- package/dist/node/pi/workflow/active-session.js.map +1 -0
- package/dist/node/pi/workflow/agent-runner.d.ts +13 -0
- package/dist/node/pi/workflow/agent-runner.d.ts.map +1 -0
- package/dist/node/pi/workflow/agent-runner.js +228 -0
- package/dist/node/pi/workflow/agent-runner.js.map +1 -0
- package/dist/node/pi/workflow/tool-journal.js +157 -0
- package/dist/node/pi/workflow/tool-journal.js.map +1 -0
- package/dist/node/pi/workflow/workflow.d.ts +29 -0
- package/dist/node/pi/workflow/workflow.d.ts.map +1 -0
- package/dist/node/pi/workflow/workflow.js +219 -0
- package/dist/node/pi/workflow/workflow.js.map +1 -0
- package/dist/node/routes.d.ts +38 -35
- package/dist/node/routes.d.ts.map +1 -1
- package/dist/node/routes.js +203 -132
- package/dist/node/routes.js.map +1 -1
- package/dist/node/schema.js +1 -1
- package/dist/node/schema.js.map +1 -1
- package/package.json +30 -29
- package/dist/browser/client-Bk-J98pf.d.ts +0 -679
- package/dist/browser/client-Bk-J98pf.d.ts.map +0 -1
- package/dist/browser/factory-DKoO_lRA.js.map +0 -1
- package/dist/browser/index.d.ts.map +0 -1
- package/dist/node/pi/clients.d.ts.map +0 -1
- package/dist/node/pi/clients.js +0 -18
- package/dist/node/pi/clients.js.map +0 -1
- package/dist/node/pi/workflow.d.ts +0 -31
- package/dist/node/pi/workflow.d.ts.map +0 -1
- package/dist/node/pi/workflow.js +0 -242
- package/dist/node/pi/workflow.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,9 +1,6 @@
|
|
|
1
|
+
import { atom, batched, computed, map, onMount, onStart, onStop, startTask, task } from "nanostores";
|
|
1
2
|
import { defineFragment, defineRoutes } from "@fragno-dev/core";
|
|
2
3
|
import { z } from "zod";
|
|
3
|
-
import { Agent } from "@mariozechner/pi-agent-core";
|
|
4
|
-
import { createAssistantMessageEventStream } from "@mariozechner/pi-ai";
|
|
5
|
-
import { NonRetryableError, defineWorkflow } from "@fragno-dev/workflows";
|
|
6
|
-
import { column, idColumn, schema } from "@fragno-dev/db/schema";
|
|
7
4
|
|
|
8
5
|
//#region ../fragno/dist/api/route.js
|
|
9
6
|
/**
|
|
@@ -19,6 +16,80 @@ function resolveRouteFactories(context, routesOrFactories) {
|
|
|
19
16
|
return routes;
|
|
20
17
|
}
|
|
21
18
|
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region ../fragno/dist/api/internal/path.js
|
|
21
|
+
/**
|
|
22
|
+
* Extract parameter names from a path pattern at runtime.
|
|
23
|
+
* Examples:
|
|
24
|
+
* - "/users/:id" => ["id"]
|
|
25
|
+
* - "/files/**" => ["**"]
|
|
26
|
+
* - "/files/**:rest" => ["rest"]
|
|
27
|
+
*/
|
|
28
|
+
function extractPathParams(pathPattern) {
|
|
29
|
+
const segments = pathPattern.split("/").filter((s) => s.length > 0);
|
|
30
|
+
const names = [];
|
|
31
|
+
for (const segment of segments) {
|
|
32
|
+
if (segment.startsWith(":")) {
|
|
33
|
+
names.push(segment.slice(1));
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (segment === "**") {
|
|
37
|
+
names.push("**");
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (segment.startsWith("**:")) {
|
|
41
|
+
names.push(segment.slice(3));
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return names;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build a concrete path by replacing placeholders in a path pattern with values.
|
|
49
|
+
*
|
|
50
|
+
* Supports the same placeholder syntax as the matcher:
|
|
51
|
+
* - Named parameter ":name" is URL-encoded as a single segment
|
|
52
|
+
* - Anonymous wildcard "**" inserts the remainder as-is (slashes preserved)
|
|
53
|
+
* - Named wildcard "**:name" inserts the remainder from the named key
|
|
54
|
+
*
|
|
55
|
+
* Examples:
|
|
56
|
+
* - buildPath("/users/:id", { id: "123" }) => "/users/123"
|
|
57
|
+
* - buildPath("/files/**", { "**": "a/b" }) => "/files/a/b"
|
|
58
|
+
* - buildPath("/files/**:rest", { rest: "a/b" }) => "/files/a/b"
|
|
59
|
+
*/
|
|
60
|
+
function buildPath(pathPattern, params) {
|
|
61
|
+
const patternSegments = pathPattern.split("/");
|
|
62
|
+
const builtSegments = [];
|
|
63
|
+
for (const segment of patternSegments) {
|
|
64
|
+
if (segment.length === 0) {
|
|
65
|
+
builtSegments.push("");
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (segment.startsWith(":")) {
|
|
69
|
+
const name = segment.slice(1);
|
|
70
|
+
const value = params[name];
|
|
71
|
+
if (value === void 0) throw new Error(`Missing value for path parameter :${name}`);
|
|
72
|
+
builtSegments.push(encodeURIComponent(value));
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (segment === "**") {
|
|
76
|
+
const value = params["**"];
|
|
77
|
+
if (value === void 0) throw new Error("Missing value for path wildcard **");
|
|
78
|
+
builtSegments.push(value);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (segment.startsWith("**:")) {
|
|
82
|
+
const name = segment.slice(3);
|
|
83
|
+
const value = params[name];
|
|
84
|
+
if (value === void 0) throw new Error(`Missing value for path wildcard **:${name}`);
|
|
85
|
+
builtSegments.push(value);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
builtSegments.push(segment);
|
|
89
|
+
}
|
|
90
|
+
return builtSegments.join("/");
|
|
91
|
+
}
|
|
92
|
+
|
|
22
93
|
//#endregion
|
|
23
94
|
//#region ../fragno/dist/api/internal/route.js
|
|
24
95
|
function getMountRoute(opts) {
|
|
@@ -449,77 +520,95 @@ var RequestOutputContext = class extends OutputContext {
|
|
|
449
520
|
};
|
|
450
521
|
|
|
451
522
|
//#endregion
|
|
452
|
-
//#region ../fragno/dist/
|
|
523
|
+
//#region ../fragno/dist/util/content-type.js
|
|
453
524
|
/**
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
* -
|
|
457
|
-
*
|
|
458
|
-
*
|
|
525
|
+
* Parses a content-type header string into its components
|
|
526
|
+
*
|
|
527
|
+
* @param contentType - The content-type header value to parse
|
|
528
|
+
* @returns A ParsedContentType object or null if the input is invalid
|
|
529
|
+
*
|
|
530
|
+
* @example
|
|
531
|
+
* ```ts
|
|
532
|
+
* const { type, subtype, mediaType, parameters }
|
|
533
|
+
* = parseContentType("application/json; charset=utf-8");
|
|
534
|
+
* console.assert(type === "application");
|
|
535
|
+
* console.assert(subtype === "json");
|
|
536
|
+
* console.assert(mediaType === "application/json");
|
|
537
|
+
* console.assert(parameters["charset"] === "utf-8");
|
|
459
538
|
*/
|
|
460
|
-
function
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
539
|
+
function parseContentType(contentType) {
|
|
540
|
+
if (!contentType || typeof contentType !== "string") return null;
|
|
541
|
+
const trimmed = contentType.trim();
|
|
542
|
+
if (!trimmed) return null;
|
|
543
|
+
const parts = trimmed.split(";").map((part) => part.trim());
|
|
544
|
+
const mediaType = parts[0];
|
|
545
|
+
if (!mediaType) return null;
|
|
546
|
+
const typeParts = mediaType.split("/");
|
|
547
|
+
if (typeParts.length !== 2) return null;
|
|
548
|
+
const [type, subtype] = typeParts.map((part) => part.trim().toLowerCase());
|
|
549
|
+
if (!type || !subtype) return null;
|
|
550
|
+
const parameters = {};
|
|
551
|
+
for (let i = 1; i < parts.length; i++) {
|
|
552
|
+
const param = parts[i];
|
|
553
|
+
const equalIndex = param.indexOf("=");
|
|
554
|
+
if (equalIndex > 0) {
|
|
555
|
+
const key = param.slice(0, equalIndex).trim().toLowerCase();
|
|
556
|
+
let value = param.slice(equalIndex + 1).trim();
|
|
557
|
+
if (value.startsWith("\"") && value.endsWith("\"")) value = value.slice(1, -1);
|
|
558
|
+
if (key) parameters[key] = value;
|
|
475
559
|
}
|
|
476
560
|
}
|
|
477
|
-
return
|
|
561
|
+
return {
|
|
562
|
+
type,
|
|
563
|
+
subtype,
|
|
564
|
+
mediaType: `${type}/${subtype}`,
|
|
565
|
+
parameters
|
|
566
|
+
};
|
|
478
567
|
}
|
|
568
|
+
|
|
569
|
+
//#endregion
|
|
570
|
+
//#region ../fragno/dist/util/nanostores.js
|
|
479
571
|
/**
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
* Supports the same placeholder syntax as the matcher:
|
|
483
|
-
* - Named parameter ":name" is URL-encoded as a single segment
|
|
484
|
-
* - Anonymous wildcard "**" inserts the remainder as-is (slashes preserved)
|
|
485
|
-
* - Named wildcard "**:name" inserts the remainder from the named key
|
|
486
|
-
*
|
|
487
|
-
* Examples:
|
|
488
|
-
* - buildPath("/users/:id", { id: "123" }) => "/users/123"
|
|
489
|
-
* - buildPath("/files/**", { "**": "a/b" }) => "/files/a/b"
|
|
490
|
-
* - buildPath("/files/**:rest", { rest: "a/b" }) => "/files/a/b"
|
|
572
|
+
* Normalizes a value that could be a plain value, an Atom, or a Vue Ref to a plain value.
|
|
491
573
|
*/
|
|
492
|
-
function
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
574
|
+
function unwrapAtom(value) {
|
|
575
|
+
if (value && typeof value === "object" && "get" in value && typeof value.get === "function") return value.get();
|
|
576
|
+
return value;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Normalizes an object where values can be plain values, Atoms, or Vue Refs.
|
|
580
|
+
* Returns a new object with all values normalized to plain values.
|
|
581
|
+
*/
|
|
582
|
+
function unwrapObject(params) {
|
|
583
|
+
if (!params) return;
|
|
584
|
+
return Object.fromEntries(Object.entries(params).map(([key, value]) => [key, unwrapAtom(value)]));
|
|
585
|
+
}
|
|
586
|
+
function isReadableAtom(value) {
|
|
587
|
+
if (!value) return false;
|
|
588
|
+
if (typeof value !== "object" || value === null) return false;
|
|
589
|
+
if (!("get" in value) || typeof value.get !== "function") return false;
|
|
590
|
+
if (!("lc" in value) || typeof value.lc !== "number") return false;
|
|
591
|
+
if (!("notify" in value) || typeof value.notify !== "function") return false;
|
|
592
|
+
if (!("off" in value) || typeof value.off !== "function") return false;
|
|
593
|
+
if (!("subscribe" in value) || typeof value.subscribe !== "function") return false;
|
|
594
|
+
if (!("value" in value)) return false;
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
//#endregion
|
|
599
|
+
//#region ../fragno/dist/util/ssr.js
|
|
600
|
+
let stores = [];
|
|
601
|
+
const SSR_ENABLED = false;
|
|
602
|
+
function addStore(store) {
|
|
603
|
+
stores.push(store);
|
|
604
|
+
}
|
|
605
|
+
let clientInitialData;
|
|
606
|
+
function getInitialData(key) {
|
|
607
|
+
if (clientInitialData?.has(key)) {
|
|
608
|
+
const data = clientInitialData.get(key);
|
|
609
|
+
clientInitialData.delete(key);
|
|
610
|
+
return data;
|
|
521
611
|
}
|
|
522
|
-
return builtSegments.join("/");
|
|
523
612
|
}
|
|
524
613
|
|
|
525
614
|
//#endregion
|
|
@@ -613,51 +702,38 @@ var FragnoClientApiError = class FragnoClientApiError extends FragnoClientError
|
|
|
613
702
|
};
|
|
614
703
|
|
|
615
704
|
//#endregion
|
|
616
|
-
//#region ../fragno/dist/
|
|
705
|
+
//#region ../fragno/dist/client/internal/fetcher-merge.js
|
|
617
706
|
/**
|
|
618
|
-
*
|
|
619
|
-
*
|
|
620
|
-
*
|
|
621
|
-
* @returns A ParsedContentType object or null if the input is invalid
|
|
622
|
-
*
|
|
623
|
-
* @example
|
|
624
|
-
* ```ts
|
|
625
|
-
* const { type, subtype, mediaType, parameters }
|
|
626
|
-
* = parseContentType("application/json; charset=utf-8");
|
|
627
|
-
* console.assert(type === "application");
|
|
628
|
-
* console.assert(subtype === "json");
|
|
629
|
-
* console.assert(mediaType === "application/json");
|
|
630
|
-
* console.assert(parameters["charset"] === "utf-8");
|
|
707
|
+
* Merge two fetcher configurations, with user config taking precedence.
|
|
708
|
+
* If user provides a custom function, it takes full precedence.
|
|
709
|
+
* Otherwise, deep merge RequestInit options.
|
|
631
710
|
*/
|
|
632
|
-
function
|
|
633
|
-
if (
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
const
|
|
637
|
-
|
|
638
|
-
if (!mediaType) return null;
|
|
639
|
-
const typeParts = mediaType.split("/");
|
|
640
|
-
if (typeParts.length !== 2) return null;
|
|
641
|
-
const [type, subtype] = typeParts.map((part) => part.trim().toLowerCase());
|
|
642
|
-
if (!type || !subtype) return null;
|
|
643
|
-
const parameters = {};
|
|
644
|
-
for (let i = 1; i < parts.length; i++) {
|
|
645
|
-
const param = parts[i];
|
|
646
|
-
const equalIndex = param.indexOf("=");
|
|
647
|
-
if (equalIndex > 0) {
|
|
648
|
-
const key = param.slice(0, equalIndex).trim().toLowerCase();
|
|
649
|
-
let value = param.slice(equalIndex + 1).trim();
|
|
650
|
-
if (value.startsWith("\"") && value.endsWith("\"")) value = value.slice(1, -1);
|
|
651
|
-
if (key) parameters[key] = value;
|
|
652
|
-
}
|
|
653
|
-
}
|
|
711
|
+
function mergeFetcherConfigs(authorConfig, userConfig) {
|
|
712
|
+
if (userConfig?.type === "function") return userConfig;
|
|
713
|
+
if (!userConfig && authorConfig?.type === "function") return authorConfig;
|
|
714
|
+
const authorOpts = authorConfig?.type === "options" ? authorConfig.options : {};
|
|
715
|
+
const userOpts = userConfig?.type === "options" ? userConfig.options : {};
|
|
716
|
+
if (Object.keys(authorOpts).length === 0 && Object.keys(userOpts).length === 0) return;
|
|
654
717
|
return {
|
|
655
|
-
type,
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
718
|
+
type: "options",
|
|
719
|
+
options: {
|
|
720
|
+
...authorOpts,
|
|
721
|
+
...userOpts,
|
|
722
|
+
headers: mergeHeaders(authorOpts.headers, userOpts.headers)
|
|
723
|
+
}
|
|
659
724
|
};
|
|
660
725
|
}
|
|
726
|
+
/**
|
|
727
|
+
* Merge headers from author and user configs.
|
|
728
|
+
* User headers override author headers.
|
|
729
|
+
*/
|
|
730
|
+
function mergeHeaders(author, user) {
|
|
731
|
+
if (!author && !user) return;
|
|
732
|
+
const merged = new Headers(author);
|
|
733
|
+
new Headers(user).forEach((value, key) => merged.set(key, value));
|
|
734
|
+
if (merged.keys().next().done) return;
|
|
735
|
+
return merged;
|
|
736
|
+
}
|
|
661
737
|
|
|
662
738
|
//#endregion
|
|
663
739
|
//#region ../fragno/dist/client/internal/ndjson-streaming.js
|
|
@@ -742,380 +818,56 @@ async function handleNdjsonStreamingFirstItem(response, store, options = {}) {
|
|
|
742
818
|
}
|
|
743
819
|
}
|
|
744
820
|
/**
|
|
745
|
-
* Continues streaming the remaining items in the background
|
|
746
|
-
*/
|
|
747
|
-
async function continueStreaming(reader, decoder, initialBuffer, items, store, abortSignal) {
|
|
748
|
-
let buffer = initialBuffer;
|
|
749
|
-
try {
|
|
750
|
-
while (true) {
|
|
751
|
-
if (abortSignal?.aborted) throw new FragnoClientFetchAbortError("Operation was aborted");
|
|
752
|
-
const { done, value } = await (abortSignal ? Promise.race([reader.read(), createAbortPromise(abortSignal)]) : reader.read());
|
|
753
|
-
if (done) {
|
|
754
|
-
if (buffer.trim()) {
|
|
755
|
-
const lines$1 = buffer.split("\n");
|
|
756
|
-
for (const line of lines$1) {
|
|
757
|
-
if (!line.trim()) continue;
|
|
758
|
-
try {
|
|
759
|
-
const jsonObject = JSON.parse(line);
|
|
760
|
-
items.push(jsonObject);
|
|
761
|
-
store?.setData([...items]);
|
|
762
|
-
} catch (parseError) {
|
|
763
|
-
throw new FragnoClientUnknownApiError("Failed to parse NDJSON line", 400, { cause: parseError });
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
break;
|
|
768
|
-
}
|
|
769
|
-
buffer += decoder.decode(value, { stream: true });
|
|
770
|
-
const lines = buffer.split("\n");
|
|
771
|
-
buffer = lines.pop() || "";
|
|
772
|
-
for (const line of lines) {
|
|
773
|
-
if (!line.trim()) continue;
|
|
774
|
-
try {
|
|
775
|
-
const jsonObject = JSON.parse(line);
|
|
776
|
-
items.push(jsonObject);
|
|
777
|
-
store?.setData([...items]);
|
|
778
|
-
} catch (parseError) {
|
|
779
|
-
throw new FragnoClientUnknownApiError("Failed to parse NDJSON line", 400, { cause: parseError });
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
} catch (error) {
|
|
784
|
-
if (error instanceof FragnoClientError) store?.setError(error);
|
|
785
|
-
else {
|
|
786
|
-
const clientError = new FragnoClientUnknownApiError("Unknown streaming error", 400, { cause: error });
|
|
787
|
-
store?.setError(clientError);
|
|
788
|
-
throw clientError;
|
|
789
|
-
}
|
|
790
|
-
throw error;
|
|
791
|
-
} finally {
|
|
792
|
-
reader.releaseLock();
|
|
793
|
-
}
|
|
794
|
-
return items;
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
//#endregion
|
|
798
|
-
//#region ../../node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/task/index.js
|
|
799
|
-
let tasks = 0;
|
|
800
|
-
let resolves = [];
|
|
801
|
-
function startTask() {
|
|
802
|
-
tasks += 1;
|
|
803
|
-
return () => {
|
|
804
|
-
tasks -= 1;
|
|
805
|
-
if (tasks === 0) {
|
|
806
|
-
let prevResolves = resolves;
|
|
807
|
-
resolves = [];
|
|
808
|
-
for (let i of prevResolves) i();
|
|
809
|
-
}
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
function task(cb) {
|
|
813
|
-
let endTask = startTask();
|
|
814
|
-
let promise = cb().finally(endTask);
|
|
815
|
-
promise.t = true;
|
|
816
|
-
return promise;
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
//#endregion
|
|
820
|
-
//#region ../../node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/clean-stores/index.js
|
|
821
|
-
let clean = Symbol("clean");
|
|
822
|
-
|
|
823
|
-
//#endregion
|
|
824
|
-
//#region ../../node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/atom/index.js
|
|
825
|
-
let listenerQueue = [];
|
|
826
|
-
let lqIndex = 0;
|
|
827
|
-
const QUEUE_ITEMS_PER_LISTENER = 4;
|
|
828
|
-
let epoch = 0;
|
|
829
|
-
const atom = /* @__NO_SIDE_EFFECTS__ */ (initialValue) => {
|
|
830
|
-
let listeners = [];
|
|
831
|
-
let $atom = {
|
|
832
|
-
get() {
|
|
833
|
-
if (!$atom.lc) $atom.listen(() => {})();
|
|
834
|
-
return $atom.value;
|
|
835
|
-
},
|
|
836
|
-
lc: 0,
|
|
837
|
-
listen(listener) {
|
|
838
|
-
$atom.lc = listeners.push(listener);
|
|
839
|
-
return () => {
|
|
840
|
-
for (let i = lqIndex + QUEUE_ITEMS_PER_LISTENER; i < listenerQueue.length;) if (listenerQueue[i] === listener) listenerQueue.splice(i, QUEUE_ITEMS_PER_LISTENER);
|
|
841
|
-
else i += QUEUE_ITEMS_PER_LISTENER;
|
|
842
|
-
let index = listeners.indexOf(listener);
|
|
843
|
-
if (~index) {
|
|
844
|
-
listeners.splice(index, 1);
|
|
845
|
-
if (!--$atom.lc) $atom.off();
|
|
846
|
-
}
|
|
847
|
-
};
|
|
848
|
-
},
|
|
849
|
-
notify(oldValue, changedKey) {
|
|
850
|
-
epoch++;
|
|
851
|
-
let runListenerQueue = !listenerQueue.length;
|
|
852
|
-
for (let listener of listeners) listenerQueue.push(listener, $atom.value, oldValue, changedKey);
|
|
853
|
-
if (runListenerQueue) {
|
|
854
|
-
for (lqIndex = 0; lqIndex < listenerQueue.length; lqIndex += QUEUE_ITEMS_PER_LISTENER) listenerQueue[lqIndex](listenerQueue[lqIndex + 1], listenerQueue[lqIndex + 2], listenerQueue[lqIndex + 3]);
|
|
855
|
-
listenerQueue.length = 0;
|
|
856
|
-
}
|
|
857
|
-
},
|
|
858
|
-
off() {},
|
|
859
|
-
set(newValue) {
|
|
860
|
-
let oldValue = $atom.value;
|
|
861
|
-
if (oldValue !== newValue) {
|
|
862
|
-
$atom.value = newValue;
|
|
863
|
-
$atom.notify(oldValue);
|
|
864
|
-
}
|
|
865
|
-
},
|
|
866
|
-
subscribe(listener) {
|
|
867
|
-
let unbind = $atom.listen(listener);
|
|
868
|
-
listener($atom.value);
|
|
869
|
-
return unbind;
|
|
870
|
-
},
|
|
871
|
-
value: initialValue
|
|
872
|
-
};
|
|
873
|
-
$atom[clean] = () => {
|
|
874
|
-
listeners = [];
|
|
875
|
-
$atom.lc = 0;
|
|
876
|
-
$atom.off();
|
|
877
|
-
};
|
|
878
|
-
return $atom;
|
|
879
|
-
};
|
|
880
|
-
|
|
881
|
-
//#endregion
|
|
882
|
-
//#region ../../node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/lifecycle/index.js
|
|
883
|
-
const START = 0;
|
|
884
|
-
const STOP = 1;
|
|
885
|
-
const MOUNT = 5;
|
|
886
|
-
const UNMOUNT = 6;
|
|
887
|
-
const REVERT_MUTATION = 10;
|
|
888
|
-
let on = (object, listener, eventKey, mutateStore) => {
|
|
889
|
-
object.events = object.events || {};
|
|
890
|
-
if (!object.events[eventKey + REVERT_MUTATION]) object.events[eventKey + REVERT_MUTATION] = mutateStore((eventProps) => {
|
|
891
|
-
object.events[eventKey].reduceRight((event, l) => (l(event), event), {
|
|
892
|
-
shared: {},
|
|
893
|
-
...eventProps
|
|
894
|
-
});
|
|
895
|
-
});
|
|
896
|
-
object.events[eventKey] = object.events[eventKey] || [];
|
|
897
|
-
object.events[eventKey].push(listener);
|
|
898
|
-
return () => {
|
|
899
|
-
let currentListeners = object.events[eventKey];
|
|
900
|
-
let index = currentListeners.indexOf(listener);
|
|
901
|
-
currentListeners.splice(index, 1);
|
|
902
|
-
if (!currentListeners.length) {
|
|
903
|
-
delete object.events[eventKey];
|
|
904
|
-
object.events[eventKey + REVERT_MUTATION]();
|
|
905
|
-
delete object.events[eventKey + REVERT_MUTATION];
|
|
906
|
-
}
|
|
907
|
-
};
|
|
908
|
-
};
|
|
909
|
-
let onStart = ($store, listener) => on($store, listener, START, (runListeners) => {
|
|
910
|
-
let originListen = $store.listen;
|
|
911
|
-
$store.listen = (arg) => {
|
|
912
|
-
if (!$store.lc && !$store.starting) {
|
|
913
|
-
$store.starting = true;
|
|
914
|
-
runListeners();
|
|
915
|
-
delete $store.starting;
|
|
916
|
-
}
|
|
917
|
-
return originListen(arg);
|
|
918
|
-
};
|
|
919
|
-
return () => {
|
|
920
|
-
$store.listen = originListen;
|
|
921
|
-
};
|
|
922
|
-
});
|
|
923
|
-
let onStop = ($store, listener) => on($store, listener, STOP, (runListeners) => {
|
|
924
|
-
let originOff = $store.off;
|
|
925
|
-
$store.off = () => {
|
|
926
|
-
runListeners();
|
|
927
|
-
originOff();
|
|
928
|
-
};
|
|
929
|
-
return () => {
|
|
930
|
-
$store.off = originOff;
|
|
931
|
-
};
|
|
932
|
-
});
|
|
933
|
-
let STORE_UNMOUNT_DELAY = 1e3;
|
|
934
|
-
let onMount = ($store, initialize) => {
|
|
935
|
-
let listener = (payload) => {
|
|
936
|
-
let destroy = initialize(payload);
|
|
937
|
-
if (destroy) $store.events[UNMOUNT].push(destroy);
|
|
938
|
-
};
|
|
939
|
-
return on($store, listener, MOUNT, (runListeners) => {
|
|
940
|
-
let originListen = $store.listen;
|
|
941
|
-
$store.listen = (...args) => {
|
|
942
|
-
if (!$store.lc && !$store.active) {
|
|
943
|
-
$store.active = true;
|
|
944
|
-
runListeners();
|
|
945
|
-
}
|
|
946
|
-
return originListen(...args);
|
|
947
|
-
};
|
|
948
|
-
let originOff = $store.off;
|
|
949
|
-
$store.events[UNMOUNT] = [];
|
|
950
|
-
$store.off = () => {
|
|
951
|
-
originOff();
|
|
952
|
-
setTimeout(() => {
|
|
953
|
-
if ($store.active && !$store.lc) {
|
|
954
|
-
$store.active = false;
|
|
955
|
-
for (let destroy of $store.events[UNMOUNT]) destroy();
|
|
956
|
-
$store.events[UNMOUNT] = [];
|
|
957
|
-
}
|
|
958
|
-
}, STORE_UNMOUNT_DELAY);
|
|
959
|
-
};
|
|
960
|
-
{
|
|
961
|
-
let originClean = $store[clean];
|
|
962
|
-
$store[clean] = () => {
|
|
963
|
-
for (let destroy of $store.events[UNMOUNT]) destroy();
|
|
964
|
-
$store.events[UNMOUNT] = [];
|
|
965
|
-
$store.active = false;
|
|
966
|
-
originClean();
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
return () => {
|
|
970
|
-
$store.listen = originListen;
|
|
971
|
-
$store.off = originOff;
|
|
972
|
-
};
|
|
973
|
-
});
|
|
974
|
-
};
|
|
975
|
-
|
|
976
|
-
//#endregion
|
|
977
|
-
//#region ../../node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/computed/index.js
|
|
978
|
-
let computedStore = (stores, cb, batched) => {
|
|
979
|
-
if (!Array.isArray(stores)) stores = [stores];
|
|
980
|
-
let previousArgs;
|
|
981
|
-
let currentEpoch;
|
|
982
|
-
let set = () => {
|
|
983
|
-
if (currentEpoch === epoch) return;
|
|
984
|
-
currentEpoch = epoch;
|
|
985
|
-
let args = stores.map(($store) => $store.get());
|
|
986
|
-
if (!previousArgs || args.some((arg, i) => arg !== previousArgs[i])) {
|
|
987
|
-
previousArgs = args;
|
|
988
|
-
let value = cb(...args);
|
|
989
|
-
if (value && value.then && value.t) value.then((asyncValue) => {
|
|
990
|
-
if (previousArgs === args) $computed.set(asyncValue);
|
|
991
|
-
});
|
|
992
|
-
else {
|
|
993
|
-
$computed.set(value);
|
|
994
|
-
currentEpoch = epoch;
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
};
|
|
998
|
-
let $computed = /* @__PURE__ */ atom(void 0);
|
|
999
|
-
let get = $computed.get;
|
|
1000
|
-
$computed.get = () => {
|
|
1001
|
-
set();
|
|
1002
|
-
return get();
|
|
1003
|
-
};
|
|
1004
|
-
let timer;
|
|
1005
|
-
let run = batched ? () => {
|
|
1006
|
-
clearTimeout(timer);
|
|
1007
|
-
timer = setTimeout(set);
|
|
1008
|
-
} : set;
|
|
1009
|
-
onMount($computed, () => {
|
|
1010
|
-
let unbinds = stores.map(($store) => $store.listen(run));
|
|
1011
|
-
set();
|
|
1012
|
-
return () => {
|
|
1013
|
-
for (let unbind of unbinds) unbind();
|
|
1014
|
-
};
|
|
1015
|
-
});
|
|
1016
|
-
return $computed;
|
|
1017
|
-
};
|
|
1018
|
-
const computed = /* @__NO_SIDE_EFFECTS__ */ (stores, fn) => computedStore(stores, fn);
|
|
1019
|
-
const batched = /* @__NO_SIDE_EFFECTS__ */ (stores, fn) => computedStore(stores, fn, true);
|
|
1020
|
-
|
|
1021
|
-
//#endregion
|
|
1022
|
-
//#region ../../node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/map/index.js
|
|
1023
|
-
const map = /* @__NO_SIDE_EFFECTS__ */ (initial = {}) => {
|
|
1024
|
-
let $map = /* @__PURE__ */ atom(initial);
|
|
1025
|
-
$map.setKey = function(key, value) {
|
|
1026
|
-
let oldMap = $map.value;
|
|
1027
|
-
if (typeof value === "undefined" && key in $map.value) {
|
|
1028
|
-
$map.value = { ...$map.value };
|
|
1029
|
-
delete $map.value[key];
|
|
1030
|
-
$map.notify(oldMap, key);
|
|
1031
|
-
} else if ($map.value[key] !== value) {
|
|
1032
|
-
$map.value = {
|
|
1033
|
-
...$map.value,
|
|
1034
|
-
[key]: value
|
|
1035
|
-
};
|
|
1036
|
-
$map.notify(oldMap, key);
|
|
1037
|
-
}
|
|
1038
|
-
};
|
|
1039
|
-
return $map;
|
|
1040
|
-
};
|
|
1041
|
-
|
|
1042
|
-
//#endregion
|
|
1043
|
-
//#region ../fragno/dist/util/ssr.js
|
|
1044
|
-
let stores = [];
|
|
1045
|
-
const SSR_ENABLED = false;
|
|
1046
|
-
function addStore(store) {
|
|
1047
|
-
stores.push(store);
|
|
1048
|
-
}
|
|
1049
|
-
let clientInitialData;
|
|
1050
|
-
function getInitialData(key) {
|
|
1051
|
-
if (clientInitialData?.has(key)) {
|
|
1052
|
-
const data = clientInitialData.get(key);
|
|
1053
|
-
clientInitialData.delete(key);
|
|
1054
|
-
return data;
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
//#endregion
|
|
1059
|
-
//#region ../fragno/dist/util/nanostores.js
|
|
1060
|
-
/**
|
|
1061
|
-
* Normalizes a value that could be a plain value, an Atom, or a Vue Ref to a plain value.
|
|
1062
|
-
*/
|
|
1063
|
-
function unwrapAtom(value) {
|
|
1064
|
-
if (value && typeof value === "object" && "get" in value && typeof value.get === "function") return value.get();
|
|
1065
|
-
return value;
|
|
1066
|
-
}
|
|
1067
|
-
/**
|
|
1068
|
-
* Normalizes an object where values can be plain values, Atoms, or Vue Refs.
|
|
1069
|
-
* Returns a new object with all values normalized to plain values.
|
|
1070
|
-
*/
|
|
1071
|
-
function unwrapObject(params) {
|
|
1072
|
-
if (!params) return;
|
|
1073
|
-
return Object.fromEntries(Object.entries(params).map(([key, value]) => [key, unwrapAtom(value)]));
|
|
1074
|
-
}
|
|
1075
|
-
function isReadableAtom(value) {
|
|
1076
|
-
if (!value) return false;
|
|
1077
|
-
if (typeof value !== "object" || value === null) return false;
|
|
1078
|
-
if (!("get" in value) || typeof value.get !== "function") return false;
|
|
1079
|
-
if (!("lc" in value) || typeof value.lc !== "number") return false;
|
|
1080
|
-
if (!("notify" in value) || typeof value.notify !== "function") return false;
|
|
1081
|
-
if (!("off" in value) || typeof value.off !== "function") return false;
|
|
1082
|
-
if (!("subscribe" in value) || typeof value.subscribe !== "function") return false;
|
|
1083
|
-
if (!("value" in value)) return false;
|
|
1084
|
-
return true;
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
//#endregion
|
|
1088
|
-
//#region ../fragno/dist/client/internal/fetcher-merge.js
|
|
1089
|
-
/**
|
|
1090
|
-
* Merge two fetcher configurations, with user config taking precedence.
|
|
1091
|
-
* If user provides a custom function, it takes full precedence.
|
|
1092
|
-
* Otherwise, deep merge RequestInit options.
|
|
1093
|
-
*/
|
|
1094
|
-
function mergeFetcherConfigs(authorConfig, userConfig) {
|
|
1095
|
-
if (userConfig?.type === "function") return userConfig;
|
|
1096
|
-
if (!userConfig && authorConfig?.type === "function") return authorConfig;
|
|
1097
|
-
const authorOpts = authorConfig?.type === "options" ? authorConfig.options : {};
|
|
1098
|
-
const userOpts = userConfig?.type === "options" ? userConfig.options : {};
|
|
1099
|
-
if (Object.keys(authorOpts).length === 0 && Object.keys(userOpts).length === 0) return;
|
|
1100
|
-
return {
|
|
1101
|
-
type: "options",
|
|
1102
|
-
options: {
|
|
1103
|
-
...authorOpts,
|
|
1104
|
-
...userOpts,
|
|
1105
|
-
headers: mergeHeaders(authorOpts.headers, userOpts.headers)
|
|
1106
|
-
}
|
|
1107
|
-
};
|
|
1108
|
-
}
|
|
1109
|
-
/**
|
|
1110
|
-
* Merge headers from author and user configs.
|
|
1111
|
-
* User headers override author headers.
|
|
821
|
+
* Continues streaming the remaining items in the background
|
|
1112
822
|
*/
|
|
1113
|
-
function
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
823
|
+
async function continueStreaming(reader, decoder, initialBuffer, items, store, abortSignal) {
|
|
824
|
+
let buffer = initialBuffer;
|
|
825
|
+
try {
|
|
826
|
+
while (true) {
|
|
827
|
+
if (abortSignal?.aborted) throw new FragnoClientFetchAbortError("Operation was aborted");
|
|
828
|
+
const { done, value } = await (abortSignal ? Promise.race([reader.read(), createAbortPromise(abortSignal)]) : reader.read());
|
|
829
|
+
if (done) {
|
|
830
|
+
if (buffer.trim()) {
|
|
831
|
+
const lines$1 = buffer.split("\n");
|
|
832
|
+
for (const line of lines$1) {
|
|
833
|
+
if (!line.trim()) continue;
|
|
834
|
+
try {
|
|
835
|
+
const jsonObject = JSON.parse(line);
|
|
836
|
+
items.push(jsonObject);
|
|
837
|
+
store?.setData([...items]);
|
|
838
|
+
} catch (parseError) {
|
|
839
|
+
throw new FragnoClientUnknownApiError("Failed to parse NDJSON line", 400, { cause: parseError });
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
break;
|
|
844
|
+
}
|
|
845
|
+
buffer += decoder.decode(value, { stream: true });
|
|
846
|
+
const lines = buffer.split("\n");
|
|
847
|
+
buffer = lines.pop() || "";
|
|
848
|
+
for (const line of lines) {
|
|
849
|
+
if (!line.trim()) continue;
|
|
850
|
+
try {
|
|
851
|
+
const jsonObject = JSON.parse(line);
|
|
852
|
+
items.push(jsonObject);
|
|
853
|
+
store?.setData([...items]);
|
|
854
|
+
} catch (parseError) {
|
|
855
|
+
throw new FragnoClientUnknownApiError("Failed to parse NDJSON line", 400, { cause: parseError });
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
} catch (error) {
|
|
860
|
+
if (error instanceof FragnoClientError) store?.setError(error);
|
|
861
|
+
else {
|
|
862
|
+
const clientError = new FragnoClientUnknownApiError("Unknown streaming error", 400, { cause: error });
|
|
863
|
+
store?.setError(clientError);
|
|
864
|
+
throw clientError;
|
|
865
|
+
}
|
|
866
|
+
throw error;
|
|
867
|
+
} finally {
|
|
868
|
+
reader.releaseLock();
|
|
869
|
+
}
|
|
870
|
+
return items;
|
|
1119
871
|
}
|
|
1120
872
|
|
|
1121
873
|
//#endregion
|
|
@@ -1134,7 +886,7 @@ let createNanoEvents = () => ({
|
|
|
1134
886
|
});
|
|
1135
887
|
|
|
1136
888
|
//#endregion
|
|
1137
|
-
//#region ../../node_modules/.pnpm/@nanostores+query@0.3.4_nanostores@1.
|
|
889
|
+
//#region ../../node_modules/.pnpm/@nanostores+query@0.3.4_nanostores@1.2.0/node_modules/@nanostores/query/dist/nanoquery.js
|
|
1138
890
|
function defaultOnErrorRetry({ retryCount }) {
|
|
1139
891
|
return ~~((Math.random() + .5) * (1 << (retryCount < 8 ? retryCount : 8))) * 2e3;
|
|
1140
892
|
}
|
|
@@ -1240,7 +992,7 @@ const nanoqueryFactory = ([isAppVisible, visibilityChangeSubscribe, reconnectCha
|
|
|
1240
992
|
};
|
|
1241
993
|
const createFetcherStore = (keyInput, { fetcher = globalFetcher, ...fetcherSettings } = {}) => {
|
|
1242
994
|
if (!fetcher) throw new Error("You need to set up either global fetcher of fetcher in createFetcherStore");
|
|
1243
|
-
const fetcherStore =
|
|
995
|
+
const fetcherStore = map({ ...notLoading }), settings = {
|
|
1244
996
|
...globalSettings,
|
|
1245
997
|
...fetcherSettings,
|
|
1246
998
|
fetcher
|
|
@@ -1400,7 +1152,7 @@ const nanoqueryFactory = ([isAppVisible, visibilityChangeSubscribe, reconnectCha
|
|
|
1400
1152
|
keysToRevalidate.forEach(revalidateKeys);
|
|
1401
1153
|
}
|
|
1402
1154
|
};
|
|
1403
|
-
const store =
|
|
1155
|
+
const store = map({
|
|
1404
1156
|
mutate,
|
|
1405
1157
|
...notLoading
|
|
1406
1158
|
});
|
|
@@ -1430,9 +1182,9 @@ const nanoqueryFactory = ([isAppVisible, visibilityChangeSubscribe, reconnectCha
|
|
|
1430
1182
|
return typeof key === "string" || typeof key === "number" || key === true;
|
|
1431
1183
|
}
|
|
1432
1184
|
const getKeyStore = (keys) => {
|
|
1433
|
-
if (isSomeKey(keys)) return [
|
|
1185
|
+
if (isSomeKey(keys)) return [atom(["" + keys, [keys]]), () => {}];
|
|
1434
1186
|
const keyParts = [];
|
|
1435
|
-
const $key =
|
|
1187
|
+
const $key = atom(null);
|
|
1436
1188
|
const keysAsStoresToIndexes = /* @__PURE__ */ new Map();
|
|
1437
1189
|
const setKeyStoreValue = () => {
|
|
1438
1190
|
if (keyParts.some((v) => v === null || v === void 0 || v === false)) $key.set(null);
|
|
@@ -1447,7 +1199,7 @@ const nanoqueryFactory = ([isAppVisible, visibilityChangeSubscribe, reconnectCha
|
|
|
1447
1199
|
}
|
|
1448
1200
|
}
|
|
1449
1201
|
const storesAsArray = [...keysAsStoresToIndexes.keys()];
|
|
1450
|
-
const $storeKeys =
|
|
1202
|
+
const $storeKeys = batched(storesAsArray, (...storeValues) => {
|
|
1451
1203
|
for (let i = 0; i < storeValues.length; i++) {
|
|
1452
1204
|
const store = storesAsArray[i], partIndex = keysAsStoresToIndexes.get(store);
|
|
1453
1205
|
keyParts[partIndex] = store._ === fetcherSymbol ? store.value && "data" in store.value ? store.key : null : storeValues[i];
|
|
@@ -1540,6 +1292,18 @@ function prepareRequestBody(body, contentType) {
|
|
|
1540
1292
|
headers: { "Content-Type": "application/json" }
|
|
1541
1293
|
};
|
|
1542
1294
|
}
|
|
1295
|
+
async function schemaAllowsUndefined(schema) {
|
|
1296
|
+
try {
|
|
1297
|
+
return !(await schema["~standard"].validate(void 0)).issues;
|
|
1298
|
+
} catch {
|
|
1299
|
+
return false;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
async function assertBodyProvided(body, inputSchema, errorMessage) {
|
|
1303
|
+
if (typeof body !== "undefined" || inputSchema === void 0) return;
|
|
1304
|
+
if (await schemaAllowsUndefined(inputSchema)) return;
|
|
1305
|
+
throw new Error(errorMessage);
|
|
1306
|
+
}
|
|
1543
1307
|
/**
|
|
1544
1308
|
* Merge request headers from multiple sources.
|
|
1545
1309
|
* Returns undefined if there are no headers to merge.
|
|
@@ -1594,7 +1358,7 @@ function getCacheKey(method, path, params) {
|
|
|
1594
1358
|
const pathParamValues = extractPathParams(path).map((name) => pathParams?.[name] ?? "<missing>");
|
|
1595
1359
|
const queryParamValues = queryParams ? Object.keys(queryParams).sort().map((key) => {
|
|
1596
1360
|
const value = queryParams[key];
|
|
1597
|
-
if (value && typeof value === "object" && "get" in value) return
|
|
1361
|
+
if (value && typeof value === "object" && "get" in value) return computed(value, (v) => v ?? "");
|
|
1598
1362
|
return value ?? "";
|
|
1599
1363
|
}) : [];
|
|
1600
1364
|
return [
|
|
@@ -1650,9 +1414,13 @@ var ClientBuilder = class {
|
|
|
1650
1414
|
get cacheEntries() {
|
|
1651
1415
|
return Object.fromEntries(this.#cache.entries());
|
|
1652
1416
|
}
|
|
1653
|
-
createStore(
|
|
1417
|
+
createStore(input) {
|
|
1418
|
+
if (typeof input === "function") return {
|
|
1419
|
+
factory: input,
|
|
1420
|
+
[STORE_SYMBOL]: true
|
|
1421
|
+
};
|
|
1654
1422
|
return {
|
|
1655
|
-
obj,
|
|
1423
|
+
obj: input,
|
|
1656
1424
|
[STORE_SYMBOL]: true
|
|
1657
1425
|
};
|
|
1658
1426
|
}
|
|
@@ -1685,7 +1453,7 @@ var ClientBuilder = class {
|
|
|
1685
1453
|
}
|
|
1686
1454
|
#getFetcher() {
|
|
1687
1455
|
if (this.#fetcherConfig?.type === "function") return this.#fetcherConfig.fetcher;
|
|
1688
|
-
return fetch;
|
|
1456
|
+
return globalThis.fetch.bind(globalThis);
|
|
1689
1457
|
}
|
|
1690
1458
|
#getFetcherOptions() {
|
|
1691
1459
|
if (this.#fetcherConfig?.type === "options") return this.#fetcherConfig.options;
|
|
@@ -1859,7 +1627,7 @@ var ClientBuilder = class {
|
|
|
1859
1627
|
const mutatorStore = this.#createMutatorStore(async ({ data }) => {
|
|
1860
1628
|
if (typeof window === "undefined") {}
|
|
1861
1629
|
const { body, path, query } = data;
|
|
1862
|
-
|
|
1630
|
+
await assertBodyProvided(body, route.inputSchema, "Body is required.");
|
|
1863
1631
|
const response = await executeMutateQuery({
|
|
1864
1632
|
body,
|
|
1865
1633
|
path,
|
|
@@ -1898,7 +1666,7 @@ var ClientBuilder = class {
|
|
|
1898
1666
|
} });
|
|
1899
1667
|
const mutateQuery = async (data) => {
|
|
1900
1668
|
const { body, path, query } = data;
|
|
1901
|
-
|
|
1669
|
+
await assertBodyProvided(body, route.inputSchema, "Body is required for mutateQuery");
|
|
1902
1670
|
const response = await executeMutateQuery({
|
|
1903
1671
|
body,
|
|
1904
1672
|
path,
|
|
@@ -1960,6 +1728,62 @@ function createClientBuilder(definition, publicConfig, routesOrFactories, author
|
|
|
1960
1728
|
//#region src/pi/definition.ts
|
|
1961
1729
|
const piFragmentDefinition = defineFragment("pi-fragment").extend((x) => x).usesService("workflows").build();
|
|
1962
1730
|
|
|
1731
|
+
//#endregion
|
|
1732
|
+
//#region src/debug-log.ts
|
|
1733
|
+
const LOG_LEVEL_PRIORITY = {
|
|
1734
|
+
off: 0,
|
|
1735
|
+
error: 1,
|
|
1736
|
+
warn: 2,
|
|
1737
|
+
info: 3,
|
|
1738
|
+
debug: 4
|
|
1739
|
+
};
|
|
1740
|
+
const DEFAULT_CONFIG = {
|
|
1741
|
+
enabled: false,
|
|
1742
|
+
level: "off"
|
|
1743
|
+
};
|
|
1744
|
+
var PiLogger = class PiLogger {
|
|
1745
|
+
static #enabled = DEFAULT_CONFIG.enabled;
|
|
1746
|
+
static #level = DEFAULT_CONFIG.level;
|
|
1747
|
+
static reset() {
|
|
1748
|
+
PiLogger.#enabled = DEFAULT_CONFIG.enabled;
|
|
1749
|
+
PiLogger.#level = DEFAULT_CONFIG.level;
|
|
1750
|
+
}
|
|
1751
|
+
static configure(config) {
|
|
1752
|
+
if (!config) return;
|
|
1753
|
+
if (config.enabled !== void 0) PiLogger.#enabled = config.enabled;
|
|
1754
|
+
if (config.level !== void 0) PiLogger.#level = config.level;
|
|
1755
|
+
}
|
|
1756
|
+
static enable() {
|
|
1757
|
+
PiLogger.#enabled = true;
|
|
1758
|
+
}
|
|
1759
|
+
static disable() {
|
|
1760
|
+
PiLogger.#enabled = false;
|
|
1761
|
+
}
|
|
1762
|
+
static setLogLevel(level) {
|
|
1763
|
+
PiLogger.#level = level;
|
|
1764
|
+
}
|
|
1765
|
+
static debug(message, fields) {
|
|
1766
|
+
PiLogger.#log("debug", message, fields);
|
|
1767
|
+
}
|
|
1768
|
+
static info(message, fields) {
|
|
1769
|
+
PiLogger.#log("info", message, fields);
|
|
1770
|
+
}
|
|
1771
|
+
static warn(message, fields) {
|
|
1772
|
+
PiLogger.#log("warn", message, fields);
|
|
1773
|
+
}
|
|
1774
|
+
static error(message, fields) {
|
|
1775
|
+
PiLogger.#log("error", message, fields);
|
|
1776
|
+
}
|
|
1777
|
+
static #log(level, message, fields) {
|
|
1778
|
+
if (!PiLogger.#enabled) return;
|
|
1779
|
+
if (LOG_LEVEL_PRIORITY[level] > LOG_LEVEL_PRIORITY[PiLogger.#level]) return;
|
|
1780
|
+
console[level](`[pi-fragment] ${message}`, {
|
|
1781
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1782
|
+
...fields
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1785
|
+
};
|
|
1786
|
+
|
|
1963
1787
|
//#endregion
|
|
1964
1788
|
//#region src/pi/constants.ts
|
|
1965
1789
|
const SESSION_STATUSES = [
|
|
@@ -1982,12 +1806,16 @@ const THINKING_LEVELS = [
|
|
|
1982
1806
|
|
|
1983
1807
|
//#endregion
|
|
1984
1808
|
//#region src/pi/route-schemas.ts
|
|
1809
|
+
const AGENT_LOOP_PHASES = [
|
|
1810
|
+
"waiting-for-user",
|
|
1811
|
+
"running-agent",
|
|
1812
|
+
"complete"
|
|
1813
|
+
];
|
|
1985
1814
|
const sessionBaseSchema = z.object({
|
|
1986
1815
|
id: z.string(),
|
|
1987
1816
|
name: z.string().nullable(),
|
|
1988
1817
|
status: z.enum(SESSION_STATUSES),
|
|
1989
1818
|
agent: z.string(),
|
|
1990
|
-
workflowInstanceId: z.string().nullable(),
|
|
1991
1819
|
steeringMode: z.enum(STEERING_MODES),
|
|
1992
1820
|
metadata: z.any().nullable(),
|
|
1993
1821
|
tags: z.array(z.string()),
|
|
@@ -2016,12 +1844,13 @@ const ToolCallSchema = z.object({
|
|
|
2016
1844
|
arguments: z.record(z.string(), z.unknown()),
|
|
2017
1845
|
thoughtSignature: z.string().optional()
|
|
2018
1846
|
});
|
|
2019
|
-
const
|
|
1847
|
+
const UserContentSchema = z.union([TextContentSchema, ImageContentSchema]);
|
|
1848
|
+
const AssistantContentSchema = z.union([
|
|
2020
1849
|
TextContentSchema,
|
|
2021
1850
|
ThinkingContentSchema,
|
|
2022
|
-
ImageContentSchema,
|
|
2023
1851
|
ToolCallSchema
|
|
2024
1852
|
]);
|
|
1853
|
+
const ToolResultContentSchema = z.union([TextContentSchema, ImageContentSchema]);
|
|
2025
1854
|
const UsageSchema = z.object({
|
|
2026
1855
|
input: z.number(),
|
|
2027
1856
|
output: z.number(),
|
|
@@ -2039,17 +1868,23 @@ const UsageSchema = z.object({
|
|
|
2039
1868
|
const MessageSchema = z.union([
|
|
2040
1869
|
z.object({
|
|
2041
1870
|
role: z.literal("user"),
|
|
2042
|
-
content: z.union([z.string(), z.array(
|
|
1871
|
+
content: z.union([z.string(), z.array(UserContentSchema)]),
|
|
2043
1872
|
timestamp: z.number()
|
|
2044
1873
|
}),
|
|
2045
1874
|
z.object({
|
|
2046
1875
|
role: z.literal("assistant"),
|
|
2047
|
-
content: z.array(
|
|
1876
|
+
content: z.array(AssistantContentSchema),
|
|
2048
1877
|
api: z.string(),
|
|
2049
1878
|
provider: z.string(),
|
|
2050
1879
|
model: z.string(),
|
|
2051
1880
|
usage: UsageSchema,
|
|
2052
|
-
stopReason: z.
|
|
1881
|
+
stopReason: z.enum([
|
|
1882
|
+
"stop",
|
|
1883
|
+
"length",
|
|
1884
|
+
"toolUse",
|
|
1885
|
+
"error",
|
|
1886
|
+
"aborted"
|
|
1887
|
+
]),
|
|
2053
1888
|
errorMessage: z.string().optional(),
|
|
2054
1889
|
timestamp: z.number()
|
|
2055
1890
|
}),
|
|
@@ -2057,16 +1892,32 @@ const MessageSchema = z.union([
|
|
|
2057
1892
|
role: z.literal("toolResult"),
|
|
2058
1893
|
toolCallId: z.string(),
|
|
2059
1894
|
toolName: z.string(),
|
|
2060
|
-
content: z.array(
|
|
1895
|
+
content: z.array(ToolResultContentSchema),
|
|
2061
1896
|
details: z.unknown().optional(),
|
|
2062
1897
|
isError: z.boolean(),
|
|
2063
1898
|
timestamp: z.number()
|
|
2064
1899
|
})
|
|
2065
1900
|
]);
|
|
2066
|
-
const TraceSchema = z.
|
|
1901
|
+
const TraceSchema = z.custom();
|
|
1902
|
+
const EventSchema = z.object({
|
|
1903
|
+
id: z.string(),
|
|
1904
|
+
runNumber: z.number().nullable().optional(),
|
|
2067
1905
|
type: z.string(),
|
|
2068
|
-
|
|
1906
|
+
payload: z.unknown().nullable(),
|
|
1907
|
+
createdAt: z.date(),
|
|
1908
|
+
deliveredAt: z.date().nullable(),
|
|
1909
|
+
consumedByStepKey: z.string().nullable()
|
|
2069
1910
|
});
|
|
1911
|
+
const WaitingForSchema = z.union([z.object({
|
|
1912
|
+
type: z.literal("user_message"),
|
|
1913
|
+
turn: z.number(),
|
|
1914
|
+
stepKey: z.string(),
|
|
1915
|
+
timeoutMs: z.number().nullable()
|
|
1916
|
+
}), z.object({
|
|
1917
|
+
type: z.literal("assistant"),
|
|
1918
|
+
turn: z.number(),
|
|
1919
|
+
stepKey: z.string()
|
|
1920
|
+
})]).nullable();
|
|
2070
1921
|
const workflowStatusSchema = z.object({
|
|
2071
1922
|
status: z.enum(SESSION_STATUSES),
|
|
2072
1923
|
error: z.object({
|
|
@@ -2078,7 +1929,11 @@ const workflowStatusSchema = z.object({
|
|
|
2078
1929
|
const sessionDetailSchema = sessionBaseSchema.extend({
|
|
2079
1930
|
workflow: workflowStatusSchema,
|
|
2080
1931
|
messages: z.array(MessageSchema),
|
|
1932
|
+
events: z.array(EventSchema),
|
|
2081
1933
|
trace: z.array(TraceSchema),
|
|
1934
|
+
turn: z.number(),
|
|
1935
|
+
phase: z.enum(AGENT_LOOP_PHASES),
|
|
1936
|
+
waitingFor: WaitingForSchema,
|
|
2082
1937
|
summaries: z.array(z.object({
|
|
2083
1938
|
turn: z.number(),
|
|
2084
1939
|
assistant: z.any().nullable(),
|
|
@@ -2086,10 +1941,13 @@ const sessionDetailSchema = sessionBaseSchema.extend({
|
|
|
2086
1941
|
}))
|
|
2087
1942
|
});
|
|
2088
1943
|
const messageAckSchema = z.object({ status: z.enum(SESSION_STATUSES) });
|
|
1944
|
+
const activeSessionStreamItemSchema = z.custom();
|
|
2089
1945
|
|
|
2090
1946
|
//#endregion
|
|
2091
1947
|
//#region src/routes.ts
|
|
2092
1948
|
const piRoutesFactory = defineRoutes(piFragmentDefinition).create(({ config, defineRoute, serviceDeps }) => {
|
|
1949
|
+
PiLogger.reset();
|
|
1950
|
+
if (config.logging) PiLogger.configure(config.logging);
|
|
2093
1951
|
return [
|
|
2094
1952
|
defineRoute({
|
|
2095
1953
|
method: "POST",
|
|
@@ -2097,16 +1955,13 @@ const piRoutesFactory = defineRoutes(piFragmentDefinition).create(({ config, def
|
|
|
2097
1955
|
inputSchema: z.object({
|
|
2098
1956
|
agent: z.string(),
|
|
2099
1957
|
name: z.string().optional(),
|
|
1958
|
+
systemMessage: z.string().optional(),
|
|
2100
1959
|
metadata: z.any().optional(),
|
|
2101
1960
|
tags: z.array(z.string()).optional(),
|
|
2102
1961
|
steeringMode: z.enum(["all", "one-at-a-time"]).optional()
|
|
2103
1962
|
}),
|
|
2104
1963
|
outputSchema: sessionBaseSchema,
|
|
2105
|
-
errorCodes: [
|
|
2106
|
-
"AGENT_NOT_FOUND",
|
|
2107
|
-
"WORKFLOWS_REQUIRED",
|
|
2108
|
-
"WORKFLOW_CREATE_FAILED"
|
|
2109
|
-
],
|
|
1964
|
+
errorCodes: ["AGENT_NOT_FOUND", "WORKFLOW_CREATE_FAILED"],
|
|
2110
1965
|
handler: () => {}
|
|
2111
1966
|
}),
|
|
2112
1967
|
defineRoute({
|
|
@@ -2119,12 +1974,20 @@ const piRoutesFactory = defineRoutes(piFragmentDefinition).create(({ config, def
|
|
|
2119
1974
|
defineRoute({
|
|
2120
1975
|
method: "GET",
|
|
2121
1976
|
path: "/sessions/:sessionId",
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
"
|
|
2125
|
-
"
|
|
2126
|
-
"WORKFLOW_INSTANCE_MISSING"
|
|
1977
|
+
queryParameters: [
|
|
1978
|
+
"events",
|
|
1979
|
+
"trace",
|
|
1980
|
+
"summaries"
|
|
2127
1981
|
],
|
|
1982
|
+
outputSchema: sessionDetailSchema,
|
|
1983
|
+
errorCodes: ["SESSION_NOT_FOUND", "WORKFLOW_INSTANCE_MISSING"],
|
|
1984
|
+
handler: () => {}
|
|
1985
|
+
}),
|
|
1986
|
+
defineRoute({
|
|
1987
|
+
method: "GET",
|
|
1988
|
+
path: "/sessions/:sessionId/active",
|
|
1989
|
+
outputSchema: z.array(activeSessionStreamItemSchema),
|
|
1990
|
+
errorCodes: ["SESSION_NOT_FOUND", "WORKFLOW_INSTANCE_MISSING"],
|
|
2128
1991
|
handler: () => {}
|
|
2129
1992
|
}),
|
|
2130
1993
|
defineRoute({
|
|
@@ -2138,7 +2001,7 @@ const piRoutesFactory = defineRoutes(piFragmentDefinition).create(({ config, def
|
|
|
2138
2001
|
outputSchema: messageAckSchema,
|
|
2139
2002
|
errorCodes: [
|
|
2140
2003
|
"SESSION_NOT_FOUND",
|
|
2141
|
-
"
|
|
2004
|
+
"SESSION_NOT_READY",
|
|
2142
2005
|
"WORKFLOW_INSTANCE_MISSING"
|
|
2143
2006
|
],
|
|
2144
2007
|
handler: () => {}
|
|
@@ -2147,53 +2010,24 @@ const piRoutesFactory = defineRoutes(piFragmentDefinition).create(({ config, def
|
|
|
2147
2010
|
});
|
|
2148
2011
|
|
|
2149
2012
|
//#endregion
|
|
2150
|
-
//#region src/
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
});
|
|
2167
|
-
});
|
|
2168
|
-
|
|
2169
|
-
//#endregion
|
|
2170
|
-
//#region src/pi/mappers.ts
|
|
2171
|
-
const normalizeSteeringMode = (value) => {
|
|
2172
|
-
return STEERING_MODES.includes(value) ? value : "one-at-a-time";
|
|
2173
|
-
};
|
|
2174
|
-
|
|
2175
|
-
//#endregion
|
|
2176
|
-
//#region src/pi/workflow.ts
|
|
2177
|
-
const PI_WORKFLOW_NAME = "agent-loop-workflow";
|
|
2178
|
-
const agentLoopParamsSchema = z.object({
|
|
2179
|
-
sessionId: z.string(),
|
|
2180
|
-
agentName: z.string(),
|
|
2181
|
-
systemPrompt: z.string().optional(),
|
|
2182
|
-
initialMessages: z.array(z.custom()).optional()
|
|
2013
|
+
//#region src/client/session-store.ts
|
|
2014
|
+
const createOverlayState = (sessionId) => ({
|
|
2015
|
+
sessionId,
|
|
2016
|
+
connection: "idle",
|
|
2017
|
+
error: null,
|
|
2018
|
+
sendError: null,
|
|
2019
|
+
sending: false,
|
|
2020
|
+
activity: { kind: "none" },
|
|
2021
|
+
pendingTurn: false,
|
|
2022
|
+
pendingSnapshotReconcile: false,
|
|
2023
|
+
readyForInputOverride: null,
|
|
2024
|
+
optimisticMessages: [],
|
|
2025
|
+
streamedMessages: [],
|
|
2026
|
+
draftAssistant: null,
|
|
2027
|
+
runningTools: [],
|
|
2028
|
+
trace: []
|
|
2183
2029
|
});
|
|
2184
|
-
const
|
|
2185
|
-
text: z.string().optional(),
|
|
2186
|
-
done: z.boolean().optional(),
|
|
2187
|
-
steeringMode: z.enum(["all", "one-at-a-time"]).optional()
|
|
2188
|
-
});
|
|
2189
|
-
const findLastAssistantMessage = (messages) => {
|
|
2190
|
-
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
2191
|
-
const message = messages[i];
|
|
2192
|
-
if (message && typeof message === "object" && "role" in message && message.role === "assistant") return message;
|
|
2193
|
-
}
|
|
2194
|
-
return null;
|
|
2195
|
-
};
|
|
2196
|
-
const buildUserMessage = (text) => ({
|
|
2030
|
+
const buildOptimisticUserMessage = (text) => ({
|
|
2197
2031
|
role: "user",
|
|
2198
2032
|
content: [{
|
|
2199
2033
|
type: "text",
|
|
@@ -2201,270 +2035,688 @@ const buildUserMessage = (text) => ({
|
|
|
2201
2035
|
}],
|
|
2202
2036
|
timestamp: Date.now()
|
|
2203
2037
|
});
|
|
2204
|
-
const
|
|
2205
|
-
role: "assistant",
|
|
2206
|
-
content: [{
|
|
2207
|
-
type: "text",
|
|
2208
|
-
text: ""
|
|
2209
|
-
}],
|
|
2210
|
-
api: model.api,
|
|
2211
|
-
provider: model.provider,
|
|
2212
|
-
model: model.id,
|
|
2213
|
-
usage: {
|
|
2214
|
-
input: 0,
|
|
2215
|
-
output: 0,
|
|
2216
|
-
cacheRead: 0,
|
|
2217
|
-
cacheWrite: 0,
|
|
2218
|
-
totalTokens: 0,
|
|
2219
|
-
cost: {
|
|
2220
|
-
input: 0,
|
|
2221
|
-
output: 0,
|
|
2222
|
-
cacheRead: 0,
|
|
2223
|
-
cacheWrite: 0,
|
|
2224
|
-
total: 0
|
|
2225
|
-
}
|
|
2226
|
-
},
|
|
2227
|
-
stopReason: "error",
|
|
2228
|
-
errorMessage: error instanceof Error ? error.message : String(error),
|
|
2229
|
-
timestamp: Date.now()
|
|
2230
|
-
});
|
|
2231
|
-
const wrapStreamFn = (streamFn) => streamFn ? async (...args) => {
|
|
2038
|
+
const formatJson = (value) => {
|
|
2232
2039
|
try {
|
|
2233
|
-
return
|
|
2234
|
-
} catch
|
|
2235
|
-
|
|
2236
|
-
const [model] = args;
|
|
2237
|
-
stream.push({
|
|
2238
|
-
type: "error",
|
|
2239
|
-
reason: "error",
|
|
2240
|
-
error: buildErrorMessage(model, error)
|
|
2241
|
-
});
|
|
2242
|
-
return stream;
|
|
2040
|
+
return JSON.stringify(value, null, 2);
|
|
2041
|
+
} catch {
|
|
2042
|
+
return String(value);
|
|
2243
2043
|
}
|
|
2244
|
-
} : void 0;
|
|
2245
|
-
const getAssistantErrorMessage = (assistant) => {
|
|
2246
|
-
if (!assistant || typeof assistant !== "object") return;
|
|
2247
|
-
if ("errorMessage" in assistant && typeof assistant.errorMessage === "string") return assistant.errorMessage;
|
|
2248
2044
|
};
|
|
2249
|
-
const
|
|
2250
|
-
const
|
|
2045
|
+
const buildLiveToolResultMessage = (message) => {
|
|
2046
|
+
const result = message.result;
|
|
2047
|
+
const content = result && Array.isArray(result.content) ? result.content : [{
|
|
2048
|
+
type: "text",
|
|
2049
|
+
text: formatJson(message.result)
|
|
2050
|
+
}];
|
|
2251
2051
|
return {
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
tags: [],
|
|
2260
|
-
createdAt: now,
|
|
2261
|
-
updatedAt: now
|
|
2052
|
+
role: "toolResult",
|
|
2053
|
+
toolCallId: message.toolCallId,
|
|
2054
|
+
toolName: message.toolName,
|
|
2055
|
+
content,
|
|
2056
|
+
details: result?.details,
|
|
2057
|
+
isError: message.isError,
|
|
2058
|
+
timestamp: Date.now()
|
|
2262
2059
|
};
|
|
2263
2060
|
};
|
|
2264
|
-
const
|
|
2265
|
-
if (
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2061
|
+
const appendOrReplaceLiveMessage = (messages, nextMessage) => {
|
|
2062
|
+
if (nextMessage.role === "assistant") {
|
|
2063
|
+
const existingIndex = messages.findIndex((message) => message.role === "assistant" && message.timestamp === nextMessage.timestamp);
|
|
2064
|
+
if (existingIndex >= 0) return [
|
|
2065
|
+
...messages.slice(0, existingIndex),
|
|
2066
|
+
nextMessage,
|
|
2067
|
+
...messages.slice(existingIndex + 1)
|
|
2068
|
+
];
|
|
2069
|
+
}
|
|
2070
|
+
if (nextMessage.role === "toolResult") {
|
|
2071
|
+
const existingIndex = messages.findIndex((message) => message.role === "toolResult" && message.toolCallId === nextMessage.toolCallId);
|
|
2072
|
+
if (existingIndex >= 0) return [
|
|
2073
|
+
...messages.slice(0, existingIndex),
|
|
2074
|
+
nextMessage,
|
|
2075
|
+
...messages.slice(existingIndex + 1)
|
|
2076
|
+
];
|
|
2077
|
+
}
|
|
2078
|
+
return [...messages, nextMessage];
|
|
2079
|
+
};
|
|
2080
|
+
const mergeMessages = (snapshotMessages, optimisticMessages, streamedMessages, draftAssistant) => {
|
|
2081
|
+
let messages = [...snapshotMessages];
|
|
2082
|
+
for (const optimisticMessage of optimisticMessages) messages = appendOrReplaceLiveMessage(messages, optimisticMessage);
|
|
2083
|
+
for (const streamedMessage of streamedMessages) messages = appendOrReplaceLiveMessage(messages, streamedMessage);
|
|
2084
|
+
if (draftAssistant) messages = appendOrReplaceLiveMessage(messages, draftAssistant);
|
|
2085
|
+
return messages;
|
|
2272
2086
|
};
|
|
2273
|
-
const
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2087
|
+
const hasActiveOverlay = (state) => state.draftAssistant !== null || state.runningTools.length > 0 || state.streamedMessages.length > 0;
|
|
2088
|
+
const activityLabel = (activity) => {
|
|
2089
|
+
switch (activity.kind) {
|
|
2090
|
+
case "none": return null;
|
|
2091
|
+
case "sending-message": return "Sending message";
|
|
2092
|
+
case "assistant-responding": return "Assistant responding";
|
|
2093
|
+
case "assistant-ready": return "Assistant response ready";
|
|
2094
|
+
case "tool-running": return `Running ${activity.toolName}`;
|
|
2095
|
+
case "tool-updating": return `Updating ${activity.toolName}`;
|
|
2096
|
+
case "tool-finished": return `${activity.toolName} finished`;
|
|
2097
|
+
case "agent-started": return "Agent started";
|
|
2098
|
+
case "agent-finished": return "Agent finished";
|
|
2099
|
+
case "turn-started": return "Turn started";
|
|
2100
|
+
case "turn-finished": return "Turn finished";
|
|
2101
|
+
default: return null;
|
|
2287
2102
|
}
|
|
2288
|
-
return resolved;
|
|
2289
2103
|
};
|
|
2290
|
-
const
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
}
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2104
|
+
const connectionStatusText = (connection) => {
|
|
2105
|
+
switch (connection) {
|
|
2106
|
+
case "connecting": return "Connecting to live updates";
|
|
2107
|
+
case "reconnecting": return "Reconnecting to live updates";
|
|
2108
|
+
default: return null;
|
|
2109
|
+
}
|
|
2110
|
+
};
|
|
2111
|
+
const reduceProtocolMessage = (state, message) => {
|
|
2112
|
+
if (message.layer === "system") switch (message.type) {
|
|
2113
|
+
case "snapshot": {
|
|
2114
|
+
const readyForInput = isSessionReadyForInput(message.phase, message.waitingFor);
|
|
2115
|
+
return {
|
|
2116
|
+
...state,
|
|
2117
|
+
error: null,
|
|
2118
|
+
activity: readyForInput ? { kind: "none" } : state.activity,
|
|
2119
|
+
pendingTurn: !readyForInput,
|
|
2120
|
+
readyForInputOverride: readyForInput
|
|
2121
|
+
};
|
|
2122
|
+
}
|
|
2123
|
+
case "inactive": return {
|
|
2124
|
+
...state,
|
|
2125
|
+
connection: "idle",
|
|
2126
|
+
error: null,
|
|
2127
|
+
readyForInputOverride: false
|
|
2128
|
+
};
|
|
2129
|
+
case "settled": return {
|
|
2130
|
+
...state,
|
|
2131
|
+
connection: "reconnecting",
|
|
2132
|
+
activity: { kind: "turn-finished" },
|
|
2133
|
+
pendingTurn: true,
|
|
2134
|
+
pendingSnapshotReconcile: true,
|
|
2135
|
+
readyForInputOverride: false,
|
|
2136
|
+
error: null
|
|
2137
|
+
};
|
|
2138
|
+
default: return state;
|
|
2139
|
+
}
|
|
2140
|
+
const event = message.event;
|
|
2141
|
+
const trace = [...state.trace, event];
|
|
2142
|
+
switch (event.type) {
|
|
2143
|
+
case "message_start":
|
|
2144
|
+
case "message_update": return {
|
|
2145
|
+
...state,
|
|
2146
|
+
trace,
|
|
2147
|
+
draftAssistant: event.message,
|
|
2148
|
+
activity: { kind: "assistant-responding" },
|
|
2149
|
+
pendingTurn: true,
|
|
2150
|
+
error: null
|
|
2151
|
+
};
|
|
2152
|
+
case "message_end": return {
|
|
2153
|
+
...state,
|
|
2154
|
+
trace,
|
|
2155
|
+
streamedMessages: appendOrReplaceLiveMessage(state.streamedMessages, event.message),
|
|
2156
|
+
draftAssistant: null,
|
|
2157
|
+
activity: { kind: "assistant-ready" },
|
|
2158
|
+
pendingTurn: true,
|
|
2159
|
+
error: null
|
|
2160
|
+
};
|
|
2161
|
+
case "tool_execution_start": return {
|
|
2162
|
+
...state,
|
|
2163
|
+
trace,
|
|
2164
|
+
runningTools: [...state.runningTools.filter((tool) => tool.toolCallId !== event.toolCallId), {
|
|
2165
|
+
toolCallId: event.toolCallId,
|
|
2166
|
+
toolName: event.toolName,
|
|
2167
|
+
args: event.args,
|
|
2168
|
+
partialResult: null
|
|
2169
|
+
}],
|
|
2170
|
+
activity: {
|
|
2171
|
+
kind: "tool-running",
|
|
2172
|
+
toolName: event.toolName
|
|
2173
|
+
},
|
|
2174
|
+
pendingTurn: true,
|
|
2175
|
+
error: null
|
|
2176
|
+
};
|
|
2177
|
+
case "tool_execution_update": return {
|
|
2178
|
+
...state,
|
|
2179
|
+
trace,
|
|
2180
|
+
runningTools: state.runningTools.map((tool) => tool.toolCallId === event.toolCallId ? {
|
|
2181
|
+
...tool,
|
|
2182
|
+
partialResult: event.partialResult
|
|
2183
|
+
} : tool),
|
|
2184
|
+
activity: {
|
|
2185
|
+
kind: "tool-updating",
|
|
2186
|
+
toolName: event.toolName
|
|
2187
|
+
},
|
|
2188
|
+
pendingTurn: true,
|
|
2189
|
+
error: null
|
|
2190
|
+
};
|
|
2191
|
+
case "tool_execution_end": return {
|
|
2192
|
+
...state,
|
|
2193
|
+
trace,
|
|
2194
|
+
streamedMessages: appendOrReplaceLiveMessage(state.streamedMessages, buildLiveToolResultMessage(event)),
|
|
2195
|
+
runningTools: state.runningTools.filter((tool) => tool.toolCallId !== event.toolCallId),
|
|
2196
|
+
activity: {
|
|
2197
|
+
kind: "tool-finished",
|
|
2198
|
+
toolName: event.toolName
|
|
2199
|
+
},
|
|
2200
|
+
pendingTurn: true,
|
|
2201
|
+
error: null
|
|
2202
|
+
};
|
|
2203
|
+
case "agent_start": return {
|
|
2204
|
+
...state,
|
|
2205
|
+
trace,
|
|
2206
|
+
activity: { kind: "agent-started" },
|
|
2207
|
+
pendingTurn: true,
|
|
2208
|
+
error: null
|
|
2209
|
+
};
|
|
2210
|
+
case "agent_end": return {
|
|
2211
|
+
...state,
|
|
2212
|
+
trace,
|
|
2213
|
+
activity: { kind: "agent-finished" },
|
|
2214
|
+
pendingTurn: true,
|
|
2215
|
+
error: null
|
|
2216
|
+
};
|
|
2217
|
+
case "turn_start": return {
|
|
2218
|
+
...state,
|
|
2219
|
+
trace,
|
|
2220
|
+
activity: { kind: "turn-started" },
|
|
2221
|
+
pendingTurn: true,
|
|
2222
|
+
error: null
|
|
2223
|
+
};
|
|
2224
|
+
case "turn_end": return {
|
|
2225
|
+
...state,
|
|
2226
|
+
trace,
|
|
2227
|
+
activity: { kind: "turn-finished" },
|
|
2228
|
+
pendingTurn: true,
|
|
2229
|
+
error: null
|
|
2230
|
+
};
|
|
2231
|
+
default: return {
|
|
2232
|
+
...state,
|
|
2233
|
+
trace,
|
|
2234
|
+
pendingTurn: true,
|
|
2235
|
+
error: null
|
|
2236
|
+
};
|
|
2237
|
+
}
|
|
2238
|
+
};
|
|
2239
|
+
const reduceOverlayState = (state, action) => {
|
|
2240
|
+
switch (action.type) {
|
|
2241
|
+
case "snapshot-updated":
|
|
2242
|
+
if (action.sessionId !== state.sessionId) return createOverlayState(action.sessionId);
|
|
2243
|
+
if (!state.pendingSnapshotReconcile) return {
|
|
2244
|
+
...state,
|
|
2245
|
+
optimisticMessages: [],
|
|
2246
|
+
sendError: null,
|
|
2247
|
+
error: null,
|
|
2248
|
+
readyForInputOverride: null
|
|
2249
|
+
};
|
|
2250
|
+
return {
|
|
2251
|
+
...state,
|
|
2252
|
+
optimisticMessages: [],
|
|
2253
|
+
streamedMessages: [],
|
|
2254
|
+
draftAssistant: null,
|
|
2255
|
+
runningTools: [],
|
|
2256
|
+
trace: [],
|
|
2257
|
+
error: null,
|
|
2258
|
+
sendError: null,
|
|
2259
|
+
activity: { kind: "none" },
|
|
2260
|
+
pendingTurn: false,
|
|
2261
|
+
pendingSnapshotReconcile: false,
|
|
2262
|
+
readyForInputOverride: null
|
|
2263
|
+
};
|
|
2264
|
+
case "send-started": return {
|
|
2265
|
+
...state,
|
|
2266
|
+
sending: true,
|
|
2267
|
+
sendError: null,
|
|
2268
|
+
optimisticMessages: [...state.optimisticMessages, {
|
|
2269
|
+
clientId: action.clientId,
|
|
2270
|
+
message: buildOptimisticUserMessage(action.text)
|
|
2271
|
+
}],
|
|
2272
|
+
activity: { kind: "sending-message" },
|
|
2273
|
+
pendingTurn: true,
|
|
2274
|
+
readyForInputOverride: false,
|
|
2275
|
+
error: null
|
|
2276
|
+
};
|
|
2277
|
+
case "send-acknowledged": return {
|
|
2278
|
+
...state,
|
|
2279
|
+
sending: false,
|
|
2280
|
+
sendError: null
|
|
2281
|
+
};
|
|
2282
|
+
case "send-failed": {
|
|
2283
|
+
const optimisticMessages = state.optimisticMessages.filter((message) => message.clientId !== action.clientId);
|
|
2284
|
+
const keepPending = state.pendingSnapshotReconcile || hasActiveOverlay(state);
|
|
2285
|
+
return {
|
|
2286
|
+
...state,
|
|
2287
|
+
sending: false,
|
|
2288
|
+
sendError: action.message,
|
|
2289
|
+
optimisticMessages,
|
|
2290
|
+
activity: keepPending ? state.activity : { kind: "none" },
|
|
2291
|
+
pendingTurn: keepPending,
|
|
2292
|
+
readyForInputOverride: keepPending ? state.readyForInputOverride : null
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
case "stream-connecting": {
|
|
2296
|
+
const connection = action.reconnecting ? "reconnecting" : "connecting";
|
|
2297
|
+
return {
|
|
2298
|
+
...state,
|
|
2299
|
+
connection,
|
|
2300
|
+
error: null
|
|
2301
|
+
};
|
|
2302
|
+
}
|
|
2303
|
+
case "stream-open": return {
|
|
2304
|
+
...state,
|
|
2305
|
+
connection: "listening",
|
|
2306
|
+
error: null
|
|
2307
|
+
};
|
|
2308
|
+
case "stream-message": return reduceProtocolMessage(state, action.message);
|
|
2309
|
+
case "stream-settled": return {
|
|
2310
|
+
...state,
|
|
2311
|
+
connection: "reconnecting"
|
|
2312
|
+
};
|
|
2313
|
+
case "stream-inactive": return {
|
|
2314
|
+
...state,
|
|
2315
|
+
connection: "idle",
|
|
2316
|
+
error: null
|
|
2317
|
+
};
|
|
2318
|
+
case "stream-error": return {
|
|
2319
|
+
...state,
|
|
2320
|
+
connection: "error",
|
|
2321
|
+
error: action.message
|
|
2322
|
+
};
|
|
2323
|
+
case "stream-idle": return {
|
|
2324
|
+
...state,
|
|
2325
|
+
connection: "idle",
|
|
2326
|
+
error: null,
|
|
2327
|
+
activity: state.pendingTurn ? state.activity : { kind: "none" }
|
|
2328
|
+
};
|
|
2329
|
+
default: return state;
|
|
2330
|
+
}
|
|
2331
|
+
};
|
|
2332
|
+
const readPiRouteError = async (response) => {
|
|
2333
|
+
const text = await response.text();
|
|
2334
|
+
if (!text) return `Request failed (${response.status}).`;
|
|
2335
|
+
try {
|
|
2336
|
+
const parsed = JSON.parse(text);
|
|
2337
|
+
return parsed.message ?? parsed.error ?? text;
|
|
2338
|
+
} catch {
|
|
2339
|
+
return text;
|
|
2340
|
+
}
|
|
2341
|
+
};
|
|
2342
|
+
const consumeProtocolStream = async (body, onMessage, signal) => {
|
|
2343
|
+
const reader = body.getReader();
|
|
2344
|
+
const decoder = new TextDecoder();
|
|
2345
|
+
let buffer = "";
|
|
2346
|
+
try {
|
|
2347
|
+
while (true) {
|
|
2348
|
+
if (signal.aborted) {
|
|
2349
|
+
await reader.cancel();
|
|
2350
|
+
return;
|
|
2351
|
+
}
|
|
2352
|
+
const { done, value } = await reader.read();
|
|
2353
|
+
if (done) break;
|
|
2354
|
+
buffer += decoder.decode(value, { stream: true });
|
|
2355
|
+
const lines = buffer.split("\n");
|
|
2356
|
+
buffer = lines.pop() ?? "";
|
|
2357
|
+
for (const line of lines) {
|
|
2358
|
+
const trimmed = line.trim();
|
|
2359
|
+
if (!trimmed) continue;
|
|
2360
|
+
onMessage(JSON.parse(trimmed));
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
const trailing = `${buffer}${decoder.decode()}`.trim();
|
|
2364
|
+
if (trailing) onMessage(JSON.parse(trailing));
|
|
2365
|
+
} finally {
|
|
2366
|
+
reader.releaseLock();
|
|
2367
|
+
}
|
|
2368
|
+
};
|
|
2369
|
+
const waitWithAbort = (ms, signal) => new Promise((resolve, reject) => {
|
|
2370
|
+
const timeoutId = setTimeout(() => {
|
|
2371
|
+
signal.removeEventListener("abort", handleAbort);
|
|
2372
|
+
resolve();
|
|
2373
|
+
}, ms);
|
|
2374
|
+
function handleAbort() {
|
|
2375
|
+
clearTimeout(timeoutId);
|
|
2376
|
+
signal.removeEventListener("abort", handleAbort);
|
|
2377
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
2378
|
+
}
|
|
2379
|
+
if (signal.aborted) {
|
|
2380
|
+
handleAbort();
|
|
2381
|
+
return;
|
|
2382
|
+
}
|
|
2383
|
+
signal.addEventListener("abort", handleAbort, { once: true });
|
|
2384
|
+
});
|
|
2385
|
+
const isSessionReadyForInput = (phase, waitingFor) => phase === "waiting-for-user" && waitingFor?.type === "user_message";
|
|
2386
|
+
const shouldKeepLiveConnection = (session) => session?.phase !== "complete";
|
|
2387
|
+
const withAcceptHeader = (defaultOptions) => {
|
|
2388
|
+
const headers = new Headers(defaultOptions?.headers);
|
|
2389
|
+
headers.set("accept", "application/x-ndjson");
|
|
2390
|
+
return {
|
|
2391
|
+
...defaultOptions,
|
|
2392
|
+
headers
|
|
2308
2393
|
};
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2394
|
+
};
|
|
2395
|
+
function createPiSessionStore(deps, args) {
|
|
2396
|
+
const detailStore = deps.createDetailStore(args.sessionId);
|
|
2397
|
+
const snapshotStore = atom(args.initialData ?? null);
|
|
2398
|
+
const overlayStore = atom(createOverlayState(args.sessionId));
|
|
2399
|
+
const lastSnapshotVersion = { current: args.initialData ? `${args.initialData.id}:${String(args.initialData.updatedAt)}` : null };
|
|
2400
|
+
let destroyed = false;
|
|
2401
|
+
let mounted = false;
|
|
2402
|
+
let activeAbortController = null;
|
|
2403
|
+
let activeLoopPromise = null;
|
|
2404
|
+
let detailUnsubscribe = null;
|
|
2405
|
+
const logActive = (event, details) => {
|
|
2406
|
+
deps.activeLogger?.(event, {
|
|
2407
|
+
sessionId: args.sessionId,
|
|
2408
|
+
...details
|
|
2409
|
+
});
|
|
2410
|
+
};
|
|
2411
|
+
const updateSnapshot = (session) => {
|
|
2412
|
+
if (!session) return;
|
|
2413
|
+
snapshotStore.set(session);
|
|
2414
|
+
const nextVersion = `${session.id}:${String(session.updatedAt)}`;
|
|
2415
|
+
if (nextVersion !== lastSnapshotVersion.current) {
|
|
2416
|
+
logActive("snapshot:updated", {
|
|
2417
|
+
version: nextVersion,
|
|
2418
|
+
phase: session.phase,
|
|
2419
|
+
status: session.status,
|
|
2420
|
+
turn: session.turn
|
|
2329
2421
|
});
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
sessionId:
|
|
2334
|
-
|
|
2335
|
-
|
|
2422
|
+
lastSnapshotVersion.current = nextVersion;
|
|
2423
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), {
|
|
2424
|
+
type: "snapshot-updated",
|
|
2425
|
+
sessionId: session.id
|
|
2426
|
+
}));
|
|
2427
|
+
}
|
|
2428
|
+
};
|
|
2429
|
+
const refetch = () => {
|
|
2430
|
+
logActive("detail:refetch");
|
|
2431
|
+
detailStore.revalidate();
|
|
2432
|
+
};
|
|
2433
|
+
const stopActiveLoop = () => {
|
|
2434
|
+
if (activeAbortController || activeLoopPromise) logActive("stream:stop");
|
|
2435
|
+
activeAbortController?.abort();
|
|
2436
|
+
activeAbortController = null;
|
|
2437
|
+
activeLoopPromise = null;
|
|
2438
|
+
};
|
|
2439
|
+
const ensureActiveLoop = () => {
|
|
2440
|
+
if (destroyed || !mounted || activeLoopPromise || deps.enableActiveStream === false) return;
|
|
2441
|
+
const currentSession = snapshotStore.get();
|
|
2442
|
+
if (!shouldKeepLiveConnection(currentSession)) {
|
|
2443
|
+
logActive("stream:idle", {
|
|
2444
|
+
reason: "session-complete",
|
|
2445
|
+
phase: currentSession?.phase ?? null,
|
|
2446
|
+
status: currentSession?.status ?? null
|
|
2336
2447
|
});
|
|
2448
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), { type: "stream-idle" }));
|
|
2449
|
+
return;
|
|
2337
2450
|
}
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2451
|
+
logActive("stream:start", {
|
|
2452
|
+
phase: currentSession?.phase ?? null,
|
|
2453
|
+
status: currentSession?.status ?? null,
|
|
2454
|
+
turn: currentSession?.turn ?? null
|
|
2455
|
+
});
|
|
2456
|
+
const abortController = new AbortController();
|
|
2457
|
+
activeAbortController = abortController;
|
|
2458
|
+
activeLoopPromise = (async () => {
|
|
2459
|
+
let reconnecting = false;
|
|
2460
|
+
while (!abortController.signal.aborted && !destroyed) {
|
|
2461
|
+
if (!shouldKeepLiveConnection(snapshotStore.get())) {
|
|
2462
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), { type: "stream-idle" }));
|
|
2463
|
+
return;
|
|
2464
|
+
}
|
|
2465
|
+
const activeUrl = deps.buildActiveUrl(args.sessionId);
|
|
2466
|
+
logActive("stream:connecting", {
|
|
2467
|
+
reconnecting,
|
|
2468
|
+
url: activeUrl
|
|
2469
|
+
});
|
|
2470
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), {
|
|
2471
|
+
type: "stream-connecting",
|
|
2472
|
+
reconnecting
|
|
2473
|
+
}));
|
|
2474
|
+
try {
|
|
2475
|
+
const response = await deps.fetcher(activeUrl, {
|
|
2476
|
+
...withAcceptHeader(deps.defaultOptions),
|
|
2477
|
+
method: "GET",
|
|
2478
|
+
cache: "no-store",
|
|
2479
|
+
signal: abortController.signal
|
|
2480
|
+
});
|
|
2481
|
+
logActive("stream:response", {
|
|
2482
|
+
ok: response.ok,
|
|
2483
|
+
status: response.status,
|
|
2484
|
+
statusText: response.statusText,
|
|
2485
|
+
url: activeUrl
|
|
2486
|
+
});
|
|
2487
|
+
if (!response.ok) throw new Error(await readPiRouteError(response));
|
|
2488
|
+
if (!response.body) throw new Error("The active session stream did not return a response body.");
|
|
2489
|
+
logActive("stream:open", { url: activeUrl });
|
|
2490
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), { type: "stream-open" }));
|
|
2491
|
+
let sawInactive = false;
|
|
2492
|
+
let sawSettled = false;
|
|
2493
|
+
await consumeProtocolStream(response.body, (message) => {
|
|
2494
|
+
logActive("stream:message", { message });
|
|
2495
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), {
|
|
2496
|
+
type: "stream-message",
|
|
2497
|
+
message
|
|
2498
|
+
}));
|
|
2499
|
+
if (message.layer === "system" && message.type === "inactive") sawInactive = true;
|
|
2500
|
+
if (message.layer === "system" && message.type === "settled") sawSettled = true;
|
|
2501
|
+
}, abortController.signal);
|
|
2502
|
+
if (abortController.signal.aborted || destroyed) return;
|
|
2503
|
+
if (sawSettled || sawInactive) {
|
|
2504
|
+
logActive("stream:settled", {
|
|
2505
|
+
sawSettled,
|
|
2506
|
+
sawInactive
|
|
2507
|
+
});
|
|
2508
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), { type: "stream-settled" }));
|
|
2509
|
+
detailStore.revalidate();
|
|
2510
|
+
}
|
|
2511
|
+
if (sawInactive) {
|
|
2512
|
+
logActive("stream:inactive");
|
|
2513
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), { type: "stream-inactive" }));
|
|
2514
|
+
return;
|
|
2515
|
+
}
|
|
2516
|
+
reconnecting = true;
|
|
2517
|
+
logActive("stream:retry", { delayMs: 250 });
|
|
2518
|
+
await waitWithAbort(250, abortController.signal);
|
|
2519
|
+
} catch (error) {
|
|
2520
|
+
if (abortController.signal.aborted || destroyed) return;
|
|
2521
|
+
const message = error instanceof Error ? error.message : "Failed to stream the active session.";
|
|
2522
|
+
logActive("stream:error", { message });
|
|
2523
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), {
|
|
2524
|
+
type: "stream-error",
|
|
2525
|
+
message
|
|
2526
|
+
}));
|
|
2527
|
+
reconnecting = true;
|
|
2528
|
+
logActive("stream:retry", { delayMs: 1e3 });
|
|
2529
|
+
await waitWithAbort(1e3, abortController.signal).catch(() => void 0);
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
})().finally(() => {
|
|
2533
|
+
logActive("stream:end");
|
|
2534
|
+
if (activeAbortController === abortController) activeAbortController = null;
|
|
2535
|
+
if (activeLoopPromise) activeLoopPromise = null;
|
|
2536
|
+
});
|
|
2348
2537
|
};
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
messages
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2538
|
+
const store = computed([
|
|
2539
|
+
detailStore,
|
|
2540
|
+
snapshotStore,
|
|
2541
|
+
overlayStore
|
|
2542
|
+
], (detailValue, session, overlay) => {
|
|
2543
|
+
const optimisticMessages = overlay.optimisticMessages.map((entry) => entry.message);
|
|
2544
|
+
const messages = mergeMessages(session?.messages ?? [], optimisticMessages, overlay.streamedMessages, overlay.draftAssistant);
|
|
2545
|
+
const statusText = activityLabel(overlay.activity) ?? connectionStatusText(overlay.connection);
|
|
2546
|
+
const readyForInput = session !== null && (overlay.readyForInputOverride ?? (isSessionReadyForInput(session.phase, session.waitingFor) && !overlay.pendingTurn));
|
|
2547
|
+
return {
|
|
2548
|
+
loading: detailValue.loading,
|
|
2549
|
+
session,
|
|
2550
|
+
messages,
|
|
2551
|
+
traceEvents: [...session?.trace ?? [], ...overlay.trace],
|
|
2552
|
+
runningTools: overlay.runningTools,
|
|
2553
|
+
connection: overlay.connection,
|
|
2554
|
+
statusText,
|
|
2555
|
+
readyForInput,
|
|
2556
|
+
sending: overlay.sending,
|
|
2557
|
+
error: detailValue.error?.message ?? overlay.error,
|
|
2558
|
+
sendError: overlay.sendError
|
|
2559
|
+
};
|
|
2560
|
+
});
|
|
2561
|
+
onMount(store, () => {
|
|
2562
|
+
mounted = true;
|
|
2563
|
+
logActive("store:mount");
|
|
2564
|
+
updateSnapshot(detailStore.get().data);
|
|
2565
|
+
detailUnsubscribe = detailStore.listen((value) => {
|
|
2566
|
+
updateSnapshot(value.data);
|
|
2567
|
+
if (destroyed) return;
|
|
2568
|
+
if (!shouldKeepLiveConnection(snapshotStore.get())) {
|
|
2569
|
+
logActive("stream:idle", { reason: "detail-store-update" });
|
|
2570
|
+
stopActiveLoop();
|
|
2571
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), { type: "stream-idle" }));
|
|
2572
|
+
return;
|
|
2573
|
+
}
|
|
2574
|
+
ensureActiveLoop();
|
|
2575
|
+
});
|
|
2576
|
+
ensureActiveLoop();
|
|
2577
|
+
return () => {
|
|
2578
|
+
logActive("store:unmount");
|
|
2579
|
+
mounted = false;
|
|
2580
|
+
stopActiveLoop();
|
|
2581
|
+
detailUnsubscribe?.();
|
|
2582
|
+
detailUnsubscribe = null;
|
|
2583
|
+
};
|
|
2359
2584
|
});
|
|
2585
|
+
const sendMessage = (input) => {
|
|
2586
|
+
const text = input.text.trim();
|
|
2587
|
+
if (!text) return false;
|
|
2588
|
+
const current = store.get();
|
|
2589
|
+
if (current.sending || !current.readyForInput) return false;
|
|
2590
|
+
const clientId = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
2591
|
+
logActive("send:start", {
|
|
2592
|
+
clientId,
|
|
2593
|
+
text
|
|
2594
|
+
});
|
|
2595
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), {
|
|
2596
|
+
type: "send-started",
|
|
2597
|
+
clientId,
|
|
2598
|
+
text
|
|
2599
|
+
}));
|
|
2600
|
+
ensureActiveLoop();
|
|
2601
|
+
deps.sendMessage({
|
|
2602
|
+
sessionId: args.sessionId,
|
|
2603
|
+
text,
|
|
2604
|
+
done: input.done,
|
|
2605
|
+
steeringMode: input.steeringMode
|
|
2606
|
+
}).then(() => {
|
|
2607
|
+
logActive("send:acknowledged", { clientId });
|
|
2608
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), { type: "send-acknowledged" }));
|
|
2609
|
+
}).catch((error) => {
|
|
2610
|
+
const message = error instanceof Error ? error.message : "Failed to send message.";
|
|
2611
|
+
logActive("send:failed", {
|
|
2612
|
+
clientId,
|
|
2613
|
+
message
|
|
2614
|
+
});
|
|
2615
|
+
overlayStore.set(reduceOverlayState(overlayStore.get(), {
|
|
2616
|
+
type: "send-failed",
|
|
2617
|
+
clientId,
|
|
2618
|
+
message
|
|
2619
|
+
}));
|
|
2620
|
+
});
|
|
2621
|
+
return true;
|
|
2622
|
+
};
|
|
2623
|
+
const deactivate = () => {
|
|
2624
|
+
logActive("store:dispose");
|
|
2625
|
+
mounted = false;
|
|
2626
|
+
stopActiveLoop();
|
|
2627
|
+
detailUnsubscribe?.();
|
|
2628
|
+
detailUnsubscribe = null;
|
|
2629
|
+
};
|
|
2630
|
+
const destroy = () => {
|
|
2631
|
+
if (destroyed) return;
|
|
2632
|
+
logActive("store:destroy");
|
|
2633
|
+
destroyed = true;
|
|
2634
|
+
deactivate();
|
|
2635
|
+
};
|
|
2360
2636
|
return {
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2637
|
+
store,
|
|
2638
|
+
sendMessage,
|
|
2639
|
+
refetch,
|
|
2640
|
+
deactivate,
|
|
2641
|
+
destroy
|
|
2364
2642
|
};
|
|
2365
|
-
}
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
while (true) {
|
|
2376
|
-
const userEvent = await step.waitForEvent(`wait-user-${turn}`, {
|
|
2377
|
-
type: "user_message",
|
|
2378
|
-
timeout: "1 hour"
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2645
|
+
//#endregion
|
|
2646
|
+
//#region src/client/session-controller.ts
|
|
2647
|
+
const select = (store, selector) => computed(store, selector);
|
|
2648
|
+
function createPiSessionControllerStore(input) {
|
|
2649
|
+
return ({ path, initialData }) => {
|
|
2650
|
+
const controller = createPiSessionStore(input, {
|
|
2651
|
+
sessionId: path.sessionId,
|
|
2652
|
+
initialData
|
|
2379
2653
|
});
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
messages,
|
|
2399
|
-
steeringMode,
|
|
2400
|
-
turnId,
|
|
2401
|
-
instanceId: event.instanceId
|
|
2402
|
-
}))).messages;
|
|
2403
|
-
if (payload.done) return { messages };
|
|
2404
|
-
turn += 1;
|
|
2405
|
-
}
|
|
2406
|
-
});
|
|
2407
|
-
const createPiWorkflows = (options) => ({ agentLoop: agentLoopWorkflow(options) });
|
|
2654
|
+
return {
|
|
2655
|
+
loading: select(controller.store, (state) => state.loading),
|
|
2656
|
+
session: select(controller.store, (state) => state.session),
|
|
2657
|
+
messages: select(controller.store, (state) => state.messages),
|
|
2658
|
+
traceEvents: select(controller.store, (state) => state.traceEvents),
|
|
2659
|
+
runningTools: select(controller.store, (state) => state.runningTools),
|
|
2660
|
+
connection: select(controller.store, (state) => state.connection),
|
|
2661
|
+
statusText: select(controller.store, (state) => state.statusText),
|
|
2662
|
+
readyForInput: select(controller.store, (state) => state.readyForInput),
|
|
2663
|
+
sending: select(controller.store, (state) => state.sending),
|
|
2664
|
+
error: select(controller.store, (state) => state.error),
|
|
2665
|
+
sendError: select(controller.store, (state) => state.sendError),
|
|
2666
|
+
sendMessage: controller.sendMessage,
|
|
2667
|
+
refetch: controller.refetch,
|
|
2668
|
+
[Symbol.dispose]: controller.deactivate
|
|
2669
|
+
};
|
|
2670
|
+
};
|
|
2671
|
+
}
|
|
2408
2672
|
|
|
2409
2673
|
//#endregion
|
|
2410
|
-
//#region src/
|
|
2411
|
-
const
|
|
2412
|
-
if (
|
|
2413
|
-
return {
|
|
2414
|
-
|
|
2415
|
-
name
|
|
2674
|
+
//#region src/client/clients.ts
|
|
2675
|
+
const createActiveSessionLogger = (enabled) => {
|
|
2676
|
+
if (!enabled) return;
|
|
2677
|
+
return (event, details) => {
|
|
2678
|
+
console.log(`[pi-active] ${event}`, details ?? {});
|
|
2416
2679
|
};
|
|
2417
2680
|
};
|
|
2418
|
-
|
|
2419
|
-
const
|
|
2420
|
-
const
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
}
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
tools: toolsSnapshot
|
|
2455
|
-
})
|
|
2456
|
-
};
|
|
2457
|
-
}
|
|
2681
|
+
function createPiFragmentClients(fragnoConfig) {
|
|
2682
|
+
const builder = createClientBuilder(piFragmentDefinition, fragnoConfig, [piRoutesFactory]);
|
|
2683
|
+
const useSessionDetail = builder.createHook("/sessions/:sessionId");
|
|
2684
|
+
const useSendMessage = builder.createMutator("POST", "/sessions/:sessionId/messages", (invalidate, params) => {
|
|
2685
|
+
const sessionId = params.pathParams.sessionId;
|
|
2686
|
+
if (!sessionId) return;
|
|
2687
|
+
invalidate("GET", "/sessions/:sessionId", { pathParams: { sessionId } });
|
|
2688
|
+
invalidate("GET", "/sessions", {});
|
|
2689
|
+
});
|
|
2690
|
+
const { fetcher, defaultOptions } = builder.getFetcher();
|
|
2691
|
+
const sessionStoreDependencies = {
|
|
2692
|
+
createDetailStore: (sessionId) => useSessionDetail.store({ path: { sessionId } }),
|
|
2693
|
+
sendMessage: ({ sessionId, text, done, steeringMode }) => useSendMessage.mutateQuery({
|
|
2694
|
+
path: { sessionId },
|
|
2695
|
+
body: {
|
|
2696
|
+
text,
|
|
2697
|
+
done,
|
|
2698
|
+
steeringMode
|
|
2699
|
+
}
|
|
2700
|
+
}).then((result) => {
|
|
2701
|
+
if (!result) throw new Error("The message mutation did not return a status response.");
|
|
2702
|
+
return result;
|
|
2703
|
+
}),
|
|
2704
|
+
buildActiveUrl: (sessionId) => builder.buildUrl("/sessions/:sessionId/active", { path: { sessionId } }),
|
|
2705
|
+
fetcher,
|
|
2706
|
+
defaultOptions,
|
|
2707
|
+
enableActiveStream: typeof window === "undefined" ? false : void 0,
|
|
2708
|
+
activeLogger: createActiveSessionLogger(fragnoConfig.debugActiveSession)
|
|
2709
|
+
};
|
|
2710
|
+
return {
|
|
2711
|
+
useSessions: builder.createHook("/sessions"),
|
|
2712
|
+
useSessionDetail,
|
|
2713
|
+
useSession: builder.createStore(createPiSessionControllerStore(sessionStoreDependencies)),
|
|
2714
|
+
useCreateSession: builder.createMutator("POST", "/sessions"),
|
|
2715
|
+
useActiveSession: builder.createHook("/sessions/:sessionId/active"),
|
|
2716
|
+
useSendMessage
|
|
2458
2717
|
};
|
|
2459
|
-
return builder;
|
|
2460
|
-
};
|
|
2461
|
-
|
|
2462
|
-
//#endregion
|
|
2463
|
-
//#region src/pi/factory.ts
|
|
2464
|
-
function createPiFragment(config, options, services) {
|
|
2465
|
-
return {};
|
|
2466
2718
|
}
|
|
2467
2719
|
|
|
2468
2720
|
//#endregion
|
|
2469
|
-
export {
|
|
2470
|
-
//# sourceMappingURL=
|
|
2721
|
+
export { STEERING_MODES as a, piFragmentDefinition as c, isStore as d, isReadableAtom as f, SESSION_STATUSES as i, isGetHook as l, createPiSessionStore as n, THINKING_LEVELS as o, piRoutesFactory as r, PiLogger as s, createPiFragmentClients as t, isMutatorHook as u };
|
|
2722
|
+
//# sourceMappingURL=clients-BscY_HVe.js.map
|