@auersperg/flare 0.3.13 → 0.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/flare.js +1 -1
- package/dist/platform/admin.js +1 -1
- package/dist/platform/dashboard/bootstrap/action.js +28 -3
- package/dist/platform/dashboard/bootstrap/openapi.json +1 -1
- package/dist/platform/dashboard/bootstrap/release.json +2 -2
- package/dist/platform/manifest.json +9 -9
- package/dist/platform/runtime.js +161 -12
- package/dist/sdk/codex.d.ts +7 -0
- package/dist/sdk/codex.js +9 -3
- package/dist/sdk/search.d.ts +30 -0
- package/dist/sdk/search.js +19 -0
- package/dist/sdk/server.d.ts +1 -1
- package/package.json +1 -1
package/dist/cli/flare.js
CHANGED
package/dist/platform/admin.js
CHANGED
|
@@ -309,7 +309,7 @@ async function collectCatalog(database, now = Date.now()) {
|
|
|
309
309
|
// packages/core/package.json
|
|
310
310
|
var package_default = {
|
|
311
311
|
name: "@flare/platform",
|
|
312
|
-
version: "0.3.
|
|
312
|
+
version: "0.3.15",
|
|
313
313
|
type: "module",
|
|
314
314
|
license: "MIT",
|
|
315
315
|
private: true,
|
|
@@ -182,8 +182,11 @@ var app_default = defineApp({ schema: {}, functions: {} });
|
|
|
182
182
|
|
|
183
183
|
// packages/flare/dist/sdk/codex.js
|
|
184
184
|
function codexInput(op, input) {
|
|
185
|
-
boundedJson(input,
|
|
186
|
-
if (!input || Array.isArray(input) || !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(input.id) || !["start", "status", "cancel"].includes(op) || Object.keys(input).some((k) => ![
|
|
185
|
+
boundedJson(input, 40000);
|
|
186
|
+
if (!input || Array.isArray(input) || !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(input.id) || !["start", "status", "cancel", "discardArtifact"].includes(op) || Object.keys(input).some((k) => ![
|
|
187
|
+
"id",
|
|
188
|
+
...op === "start" ? ["prompt", "instructions", "outputFile"] : []
|
|
189
|
+
].includes(k)) || op === "start" && (typeof input.prompt !== "string" || !input.prompt.trim() || new TextEncoder().encode(input.prompt).length > 16384 || input.instructions !== undefined && (typeof input.instructions !== "string" || new TextEncoder().encode(input.instructions).length > 16384) || input.outputFile !== undefined && (typeof input.outputFile !== "string" || !/^[a-zA-Z0-9_-]{1,64}\.json$/.test(input.outputFile))))
|
|
187
190
|
throw new FlareError("INVALID_ARGUMENT", "Invalid Codex task");
|
|
188
191
|
}
|
|
189
192
|
function codexContext(call) {
|
|
@@ -194,13 +197,35 @@ function codexContext(call) {
|
|
|
194
197
|
return {
|
|
195
198
|
start: (input) => invoke("start", input),
|
|
196
199
|
status: (id) => invoke("status", { id }),
|
|
197
|
-
cancel: (id) => invoke("cancel", { id })
|
|
200
|
+
cancel: (id) => invoke("cancel", { id }),
|
|
201
|
+
discardArtifact: async (id) => {
|
|
202
|
+
await invoke("discardArtifact", { id });
|
|
203
|
+
}
|
|
198
204
|
};
|
|
199
205
|
}
|
|
200
206
|
|
|
201
207
|
// packages/flare/dist/sdk/search.js
|
|
202
208
|
function searchContext(command) {
|
|
203
209
|
return {
|
|
210
|
+
records: {
|
|
211
|
+
sync: (input) => command("record-sync", input),
|
|
212
|
+
status: (input) => command("record-status", input),
|
|
213
|
+
async query(input, authorize) {
|
|
214
|
+
if (typeof authorize !== "function")
|
|
215
|
+
throw new FlareError("FORBIDDEN", "A current source access/version check is required");
|
|
216
|
+
const hits = await command("record-query", input);
|
|
217
|
+
if (!hits.length)
|
|
218
|
+
return [];
|
|
219
|
+
const allowed = await authorize(hits.map(({ id, version }) => ({ id, version })));
|
|
220
|
+
if (!Array.isArray(allowed) || allowed.some((a) => !hits.some((h) => h.id === a.id && h.version === a.version)))
|
|
221
|
+
throw new FlareError("FORBIDDEN", "Invalid source access result");
|
|
222
|
+
const current = await command("record-validate", {
|
|
223
|
+
partition: input.partition,
|
|
224
|
+
records: allowed
|
|
225
|
+
});
|
|
226
|
+
return hits.filter((h) => current.some((a) => a.id === h.id && a.version === h.version));
|
|
227
|
+
}
|
|
228
|
+
},
|
|
204
229
|
index: (fileId) => command("index", { fileId }),
|
|
205
230
|
exclude: (fileId) => command("exclude", { fileId }),
|
|
206
231
|
status: (fileId) => command("status", { fileId }),
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Flare application contract",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "46e95c497319ce515538fb3788f93111df98c76d7ca3eafbc6fd8bcbb4cfbff1"
|
|
6
6
|
},
|
|
7
7
|
"components": {
|
|
8
8
|
"schemas": {},
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"compatibilityDate": "2026-10-10",
|
|
4
4
|
"checksums": {
|
|
5
5
|
"facet": "8d7880b99b69d141a58da4c7574b26c39dbc529785512298683239dee657a38b",
|
|
6
|
-
"action": "
|
|
6
|
+
"action": "551610f76cc588409c0d5f51f23b132a7da1d90f851d49fea5186f6c8e5f7383",
|
|
7
7
|
"schema": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
|
|
8
8
|
"manifest": "006a07907dfd7619fa66152627bc761e581cf8ac538f5002f3b89b71ce92d733"
|
|
9
9
|
},
|
|
10
|
-
"hash": "
|
|
10
|
+
"hash": "46e95c497319ce515538fb3788f93111df98c76d7ca3eafbc6fd8bcbb4cfbff1"
|
|
11
11
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": 1,
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.15",
|
|
4
4
|
"stateFormat": 1,
|
|
5
5
|
"protocol": 1,
|
|
6
6
|
"runtimeAbi": 4,
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
{
|
|
14
14
|
"path": "admin.js",
|
|
15
15
|
"bytes": 37491,
|
|
16
|
-
"sha256": "
|
|
16
|
+
"sha256": "4fe2f7a229b217bfc26c0ec5708f6ae1b06306dcacdc1068f642abc901202d5a"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "dashboard/_astro/ai-view.D6ouaMiL.js",
|
|
@@ -122,8 +122,8 @@
|
|
|
122
122
|
},
|
|
123
123
|
{
|
|
124
124
|
"path": "dashboard/bootstrap/action.js",
|
|
125
|
-
"bytes":
|
|
126
|
-
"sha256": "
|
|
125
|
+
"bytes": 13801,
|
|
126
|
+
"sha256": "551610f76cc588409c0d5f51f23b132a7da1d90f851d49fea5186f6c8e5f7383"
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"path": "dashboard/bootstrap/api.ts",
|
|
@@ -143,12 +143,12 @@
|
|
|
143
143
|
{
|
|
144
144
|
"path": "dashboard/bootstrap/openapi.json",
|
|
145
145
|
"bytes": 362,
|
|
146
|
-
"sha256": "
|
|
146
|
+
"sha256": "d9672f489689ae8053324a9599477a438495609b1034f52b4599f1a154f4f157"
|
|
147
147
|
},
|
|
148
148
|
{
|
|
149
149
|
"path": "dashboard/bootstrap/release.json",
|
|
150
150
|
"bytes": 484,
|
|
151
|
-
"sha256": "
|
|
151
|
+
"sha256": "46bd000ed0f4b7fe3b3e71d3555849103a773bf8b434af5e52e3060e5d5e4630"
|
|
152
152
|
},
|
|
153
153
|
{
|
|
154
154
|
"path": "dashboard/bootstrap/schema.json",
|
|
@@ -192,9 +192,9 @@
|
|
|
192
192
|
},
|
|
193
193
|
{
|
|
194
194
|
"path": "runtime.js",
|
|
195
|
-
"bytes":
|
|
196
|
-
"sha256": "
|
|
195
|
+
"bytes": 1229444,
|
|
196
|
+
"sha256": "3ffb8eb5dafee479a222d97cb661e49f6f4f919b2f8403ec3d2f689cb5d15082"
|
|
197
197
|
}
|
|
198
198
|
],
|
|
199
|
-
"digest": "
|
|
199
|
+
"digest": "53eb87d966d0698a5dab31c3bb1d3279e170df76d77ddcb67e5d8e5190c7b374"
|
|
200
200
|
}
|
package/dist/platform/runtime.js
CHANGED
|
@@ -23057,8 +23057,11 @@ async function outbound(request, policy) {
|
|
|
23057
23057
|
|
|
23058
23058
|
// packages/flare/src/sdk/codex.ts
|
|
23059
23059
|
function codexInput(op, input) {
|
|
23060
|
-
boundedJson(input,
|
|
23061
|
-
if (!input || Array.isArray(input) || !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(input.id) || !["start", "status", "cancel"].includes(op) || Object.keys(input).some((k) => ![
|
|
23060
|
+
boundedJson(input, 40000);
|
|
23061
|
+
if (!input || Array.isArray(input) || !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(input.id) || !["start", "status", "cancel", "discardArtifact"].includes(op) || Object.keys(input).some((k) => ![
|
|
23062
|
+
"id",
|
|
23063
|
+
...op === "start" ? ["prompt", "instructions", "outputFile"] : []
|
|
23064
|
+
].includes(k)) || op === "start" && (typeof input.prompt !== "string" || !input.prompt.trim() || new TextEncoder().encode(input.prompt).length > 16384 || input.instructions !== undefined && (typeof input.instructions !== "string" || new TextEncoder().encode(input.instructions).length > 16384) || input.outputFile !== undefined && (typeof input.outputFile !== "string" || !/^[a-zA-Z0-9_-]{1,64}\.json$/.test(input.outputFile))))
|
|
23062
23065
|
throw new FlareError("INVALID_ARGUMENT", "Invalid Codex task");
|
|
23063
23066
|
}
|
|
23064
23067
|
|
|
@@ -23626,12 +23629,38 @@ class SearchStore {
|
|
|
23626
23629
|
}
|
|
23627
23630
|
static initialize(storage) {
|
|
23628
23631
|
storage.sql.exec("CREATE TABLE IF NOT EXISTS search_items (id TEXT PRIMARY KEY,key TEXT NOT NULL,version TEXT NOT NULL,binding TEXT NOT NULL,item TEXT,status TEXT NOT NULL,wanted INTEGER NOT NULL,attempts INTEGER NOT NULL DEFAULT 0,uncertain INTEGER NOT NULL DEFAULT 0,error TEXT)");
|
|
23632
|
+
const columns = new Set(storage.sql.exec("PRAGMA table_info(search_items)").toArray().map((r) => r.name));
|
|
23633
|
+
for (const name of ["record_id", "partition", "text", "metadata"])
|
|
23634
|
+
if (!columns.has(name))
|
|
23635
|
+
storage.sql.exec(`ALTER TABLE search_items ADD COLUMN ${name} TEXT`);
|
|
23636
|
+
storage.sql.exec("CREATE TABLE IF NOT EXISTS search_records (id TEXT NOT NULL,partition TEXT NOT NULL,version INTEGER NOT NULL,digest TEXT NOT NULL,wanted INTEGER NOT NULL,current TEXT,PRIMARY KEY(id,partition))");
|
|
23637
|
+
storage.sql.exec("CREATE INDEX IF NOT EXISTS search_record_versions ON search_items(record_id,partition)");
|
|
23638
|
+
}
|
|
23639
|
+
head(id, partition) {
|
|
23640
|
+
this.recordRef(id, partition);
|
|
23641
|
+
return this.storage.sql.exec("SELECT * FROM search_records WHERE id=? AND partition=?", id, partition).toArray()[0];
|
|
23642
|
+
}
|
|
23643
|
+
recordRef(id, partition) {
|
|
23644
|
+
fileKey(this.scope, id);
|
|
23645
|
+
if (typeof partition !== "string" || !partition || new TextEncoder().encode(partition).length > 128)
|
|
23646
|
+
fail("INVALID_INPUT");
|
|
23647
|
+
}
|
|
23648
|
+
async hash(value) {
|
|
23649
|
+
return Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value)))).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
23650
|
+
}
|
|
23651
|
+
async folder(partition) {
|
|
23652
|
+
return (await this.hash(JSON.stringify([this.scope, partition]))).slice(0, 32) + "/";
|
|
23629
23653
|
}
|
|
23630
23654
|
row(id) {
|
|
23631
23655
|
fileKey(this.scope, id);
|
|
23632
23656
|
return this.storage.sql.exec("SELECT * FROM search_items WHERE id=?", id).toArray()[0];
|
|
23633
23657
|
}
|
|
23634
23658
|
original(id) {
|
|
23659
|
+
const row = this.row(id);
|
|
23660
|
+
if (row?.record_id) {
|
|
23661
|
+
const head = this.head(row.record_id, row.partition);
|
|
23662
|
+
return head?.wanted && head.current === id ? { name: row.record_id, type: "text/plain" } : undefined;
|
|
23663
|
+
}
|
|
23635
23664
|
return this.storage.sql.exec("SELECT name,type FROM files WHERE id=? AND state='ready'", id).toArray()[0];
|
|
23636
23665
|
}
|
|
23637
23666
|
binding(name = appPolicy(this.env, this.scope).search) {
|
|
@@ -23652,7 +23681,7 @@ class SearchStore {
|
|
|
23652
23681
|
};
|
|
23653
23682
|
}
|
|
23654
23683
|
async reconcile() {
|
|
23655
|
-
this.storage.sql.exec("UPDATE search_items SET wanted=0,attempts=0,error=NULL WHERE binding!=? AND wanted=1", appPolicy(this.env, this.scope).search ?? "");
|
|
23684
|
+
this.storage.sql.exec("UPDATE search_items SET wanted=0,attempts=0,error=NULL,text=NULL,metadata=NULL WHERE binding!=? AND wanted=1", appPolicy(this.env, this.scope).search ?? "");
|
|
23656
23685
|
this.storage.sql.exec("UPDATE search_items SET status='error',error=COALESCE(error,'SEARCH_RECONCILE_REQUIRED') WHERE (wanted=0 OR status IN ('pending','sending')) AND attempts>=3");
|
|
23657
23686
|
if (this.storage.sql.exec("SELECT 1 FROM search_items WHERE (wanted=0 OR status IN ('pending','sending')) AND attempts<3 LIMIT 1").toArray().length)
|
|
23658
23687
|
await this.wake();
|
|
@@ -23697,7 +23726,8 @@ class SearchStore {
|
|
|
23697
23726
|
return this.state(id);
|
|
23698
23727
|
}
|
|
23699
23728
|
async clear() {
|
|
23700
|
-
this.storage.sql.exec("UPDATE
|
|
23729
|
+
this.storage.sql.exec("UPDATE search_records SET wanted=0");
|
|
23730
|
+
this.storage.sql.exec("UPDATE search_items SET wanted=0,attempts=0,error=NULL,text=NULL,metadata=NULL");
|
|
23701
23731
|
await this.wake();
|
|
23702
23732
|
return this.summary();
|
|
23703
23733
|
}
|
|
@@ -23718,6 +23748,8 @@ class SearchStore {
|
|
|
23718
23748
|
updateInfo(row, info) {
|
|
23719
23749
|
if (info.key !== row.key || !states.has(info.status))
|
|
23720
23750
|
fail("SEARCH_UNAVAILABLE");
|
|
23751
|
+
if (row.record_id && ["queued", "running", "completed"].includes(info.status))
|
|
23752
|
+
this.storage.sql.exec("UPDATE search_items SET text=NULL WHERE id=?", row.id);
|
|
23721
23753
|
this.storage.sql.exec("UPDATE search_items SET item=?,status=?,error=?,uncertain=0 WHERE id=? AND key=? AND wanted=1", info.id, info.status, info.status === "error" ? "INDEXING_FAILED" : null, row.id, row.key);
|
|
23722
23754
|
this.storage.sql.exec("UPDATE search_items SET item=?,uncertain=0 WHERE id=? AND key=? AND wanted=0", info.id, row.id, row.key);
|
|
23723
23755
|
}
|
|
@@ -23791,6 +23823,113 @@ class SearchStore {
|
|
|
23791
23823
|
boundedJson(hits, LIMITS.outputBytes);
|
|
23792
23824
|
return hits;
|
|
23793
23825
|
}
|
|
23826
|
+
async syncRecord(input) {
|
|
23827
|
+
boundedJson(input, 20000);
|
|
23828
|
+
if (!input || Object.keys(input).some((k) => !["id", "partition", "version", "text", "metadata"].includes(k)))
|
|
23829
|
+
fail("INVALID_INPUT");
|
|
23830
|
+
this.recordRef(input.id, input.partition);
|
|
23831
|
+
if (!Number.isSafeInteger(input.version) || input.version < 1 || input.text !== null && (typeof input.text !== "string" || !input.text.trim() || new TextEncoder().encode(input.text).length > 16384))
|
|
23832
|
+
fail("INVALID_INPUT");
|
|
23833
|
+
const metadata = input.metadata ?? {};
|
|
23834
|
+
if (!metadata || Array.isArray(metadata) || typeof metadata !== "object" || Object.keys(metadata).length > 5 || Object.entries(metadata).some(([k, v]) => !/^[a-z][a-z0-9_]{0,31}$/.test(k) || ["folder", "filename", "timestamp"].includes(k) || typeof v !== "string" || new TextEncoder().encode(v).length > 64))
|
|
23835
|
+
fail("INVALID_INPUT");
|
|
23836
|
+
const digest = await this.hash(stableJson({ text: input.text, metadata }));
|
|
23837
|
+
const folder = await this.folder(input.partition);
|
|
23838
|
+
const head = this.head(input.id, input.partition);
|
|
23839
|
+
const binding = appPolicy(this.env, this.scope).search;
|
|
23840
|
+
if (head && input.version < head.version)
|
|
23841
|
+
return this.recordState(input);
|
|
23842
|
+
if (head && input.version === head.version && (digest !== head.digest || Boolean(head.wanted) !== (input.text !== null)))
|
|
23843
|
+
fail("CONFLICT");
|
|
23844
|
+
const current = head?.current ? this.row(head.current) : undefined;
|
|
23845
|
+
if (input.text !== null)
|
|
23846
|
+
this.binding(binding);
|
|
23847
|
+
if (head?.version === input.version && (input.text === null || current?.wanted && current.binding === binding)) {
|
|
23848
|
+
if (current && ["error", "skipped", "outdated"].includes(current.status))
|
|
23849
|
+
this.storage.sql.exec("UPDATE search_items SET status='pending',attempts=0,error=NULL,text=? WHERE id=?", input.text, current.id);
|
|
23850
|
+
await this.wake();
|
|
23851
|
+
return this.recordState(input);
|
|
23852
|
+
}
|
|
23853
|
+
this.storage.sql.exec("UPDATE search_items SET wanted=0,text=NULL,metadata=NULL,attempts=0,error=NULL WHERE record_id=? AND partition=?", input.id, input.partition);
|
|
23854
|
+
const id = input.text === null ? null : crypto.randomUUID();
|
|
23855
|
+
if (id)
|
|
23856
|
+
this.storage.sql.exec("INSERT INTO search_items (id,key,version,binding,status,wanted,record_id,partition,text,metadata) VALUES (?,?,?,?,'pending',1,?,?,?,?)", id, folder + id + ".txt", String(input.version), binding, input.id, input.partition, input.text, Object.keys(metadata).length ? JSON.stringify(metadata) : null);
|
|
23857
|
+
this.storage.sql.exec("INSERT OR REPLACE INTO search_records VALUES (?,?,?,?,?,?)", input.id, input.partition, input.version, digest, Number(input.text !== null), id);
|
|
23858
|
+
await this.wake();
|
|
23859
|
+
return this.recordState(input);
|
|
23860
|
+
}
|
|
23861
|
+
recordState(input) {
|
|
23862
|
+
const head = this.head(input.id, input.partition);
|
|
23863
|
+
const row = head?.current ? this.row(head.current) : undefined;
|
|
23864
|
+
const pending = this.storage.sql.exec("SELECT error FROM search_items WHERE record_id=? AND partition=? AND wanted=0", input.id, input.partition).toArray();
|
|
23865
|
+
return {
|
|
23866
|
+
id: input.id,
|
|
23867
|
+
version: head?.version ?? 0,
|
|
23868
|
+
enabled: Boolean(head?.wanted && row?.wanted && row.binding === appPolicy(this.env, this.scope).search),
|
|
23869
|
+
status: head?.wanted && row?.wanted ? row.status : pending.length ? "deleting" : "excluded",
|
|
23870
|
+
error: row?.error ?? pending.find((r) => r.error)?.error ?? null
|
|
23871
|
+
};
|
|
23872
|
+
}
|
|
23873
|
+
async recordStatus(input) {
|
|
23874
|
+
const head = this.head(input.id, input.partition);
|
|
23875
|
+
if (head?.current)
|
|
23876
|
+
await this.status(head.current);
|
|
23877
|
+
return this.recordState(input);
|
|
23878
|
+
}
|
|
23879
|
+
validateRecords(input) {
|
|
23880
|
+
if (!Array.isArray(input?.records) || input.records.length > 20)
|
|
23881
|
+
fail("INVALID_INPUT");
|
|
23882
|
+
return input.records.filter(({ id, version }) => {
|
|
23883
|
+
const head = this.head(id, input.partition);
|
|
23884
|
+
const row = head?.current ? this.row(head.current) : undefined;
|
|
23885
|
+
return head?.wanted && head.version === version && row?.wanted && row.binding === appPolicy(this.env, this.scope).search;
|
|
23886
|
+
});
|
|
23887
|
+
}
|
|
23888
|
+
async queryRecords(input) {
|
|
23889
|
+
boundedJson(input, 1e4);
|
|
23890
|
+
if (!input || typeof input.query !== "string" || !input.query.trim() || input.query.length > 2000 || Object.keys(input).some((k) => !["query", "partition", "limit"].includes(k)))
|
|
23891
|
+
fail("INVALID_INPUT");
|
|
23892
|
+
this.recordRef("00000000-0000-4000-8000-000000000000", input.partition);
|
|
23893
|
+
const limit = input.limit ?? 10;
|
|
23894
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 20)
|
|
23895
|
+
fail("INVALID_INPUT");
|
|
23896
|
+
const binding = appPolicy(this.env, this.scope).search;
|
|
23897
|
+
const instance = this.binding(binding);
|
|
23898
|
+
const folder = await this.folder(input.partition);
|
|
23899
|
+
let result;
|
|
23900
|
+
try {
|
|
23901
|
+
result = await instance.search({
|
|
23902
|
+
query: input.query,
|
|
23903
|
+
ai_search_options: {
|
|
23904
|
+
retrieval: {
|
|
23905
|
+
max_num_results: limit,
|
|
23906
|
+
return_on_failure: false,
|
|
23907
|
+
filters: { folder }
|
|
23908
|
+
},
|
|
23909
|
+
query_rewrite: { enabled: false },
|
|
23910
|
+
reranking: { enabled: false },
|
|
23911
|
+
cache: { enabled: false }
|
|
23912
|
+
}
|
|
23913
|
+
});
|
|
23914
|
+
} catch {
|
|
23915
|
+
fail("SEARCH_UNAVAILABLE");
|
|
23916
|
+
}
|
|
23917
|
+
const hits = [];
|
|
23918
|
+
for (const chunk of result.chunks.slice(0, limit)) {
|
|
23919
|
+
const row = this.storage.sql.exec("SELECT s.record_id,h.version FROM search_items s JOIN search_records h ON h.current=s.id WHERE s.key=? AND s.binding=? AND s.partition=? AND s.wanted=1 AND h.wanted=1", chunk.item.key, binding, input.partition).toArray()[0];
|
|
23920
|
+
if (!row)
|
|
23921
|
+
continue;
|
|
23922
|
+
if (typeof chunk.text !== "string" || !Number.isFinite(chunk.score))
|
|
23923
|
+
fail("SEARCH_UNAVAILABLE");
|
|
23924
|
+
hits.push({
|
|
23925
|
+
id: String(row.record_id),
|
|
23926
|
+
version: Number(row.version),
|
|
23927
|
+
text: chunk.text.slice(0, 2000),
|
|
23928
|
+
score: chunk.score
|
|
23929
|
+
});
|
|
23930
|
+
}
|
|
23931
|
+
return hits;
|
|
23932
|
+
}
|
|
23794
23933
|
work() {
|
|
23795
23934
|
return this.working ??= this.process().finally(() => {
|
|
23796
23935
|
this.working = undefined;
|
|
@@ -23833,21 +23972,23 @@ class SearchStore {
|
|
|
23833
23972
|
if (existing[0] && !["error", "skipped", "outdated"].includes(existing[0].status)) {
|
|
23834
23973
|
this.updateInfo(row, existing[0]);
|
|
23835
23974
|
} else {
|
|
23836
|
-
const object = await this.env.FILES?.get(fileKey(this.scope, row.id));
|
|
23837
|
-
|
|
23975
|
+
const object = row.record_id ? null : await this.env.FILES?.get(fileKey(this.scope, row.id));
|
|
23976
|
+
const content = row.record_id ? this.row(row.id)?.text : object?.body;
|
|
23977
|
+
if (content == null)
|
|
23838
23978
|
fail("NOT_FOUND");
|
|
23839
|
-
if (row.version && object.version !== row.version) {
|
|
23979
|
+
if (object && row.version && object.version !== row.version) {
|
|
23840
23980
|
await object.body.cancel();
|
|
23841
23981
|
fail("NOT_FOUND");
|
|
23842
23982
|
}
|
|
23843
23983
|
if (!this.row(row.id)?.wanted || !this.original(row.id)) {
|
|
23844
|
-
await object
|
|
23984
|
+
await object?.body.cancel();
|
|
23845
23985
|
continue;
|
|
23846
23986
|
}
|
|
23847
|
-
this.storage.sql.exec("UPDATE search_items SET status='sending',uncertain=1,version=? WHERE id=? AND wanted=1", object.version, row.id);
|
|
23848
|
-
this.updateInfo(row, await instance.items.uploadAndPoll(row.key,
|
|
23987
|
+
this.storage.sql.exec("UPDATE search_items SET status='sending',uncertain=1,version=? WHERE id=? AND wanted=1", object?.version ?? row.version, row.id);
|
|
23988
|
+
this.updateInfo(row, await instance.items.uploadAndPoll(row.key, content, {
|
|
23849
23989
|
timeoutMs: 30000,
|
|
23850
|
-
pollIntervalMs: 2000
|
|
23990
|
+
pollIntervalMs: 2000,
|
|
23991
|
+
...row.metadata ? { metadata: JSON.parse(row.metadata) } : {}
|
|
23851
23992
|
}));
|
|
23852
23993
|
}
|
|
23853
23994
|
} catch (error) {
|
|
@@ -24208,7 +24349,7 @@ function dashboardIdentity(value) {
|
|
|
24208
24349
|
// packages/core/package.json
|
|
24209
24350
|
var package_default = {
|
|
24210
24351
|
name: "@flare/platform",
|
|
24211
|
-
version: "0.3.
|
|
24352
|
+
version: "0.3.15",
|
|
24212
24353
|
type: "module",
|
|
24213
24354
|
license: "MIT",
|
|
24214
24355
|
private: true,
|
|
@@ -32605,6 +32746,14 @@ class EnvironmentSupervisor extends DurableObject {
|
|
|
32605
32746
|
async searchCommand(op, input) {
|
|
32606
32747
|
await this.lifecycle.start();
|
|
32607
32748
|
this.assertAvailable();
|
|
32749
|
+
if (op === "record-sync")
|
|
32750
|
+
return this.search().syncRecord(input);
|
|
32751
|
+
if (op === "record-status")
|
|
32752
|
+
return this.search().recordStatus(input);
|
|
32753
|
+
if (op === "record-query")
|
|
32754
|
+
return this.search().queryRecords(input);
|
|
32755
|
+
if (op === "record-validate")
|
|
32756
|
+
return this.search().validateRecords(input);
|
|
32608
32757
|
if (op === "index")
|
|
32609
32758
|
return this.search().index(input.fileId);
|
|
32610
32759
|
if (op === "exclude")
|
package/dist/sdk/codex.d.ts
CHANGED
|
@@ -2,6 +2,10 @@ export interface CodexTaskInput {
|
|
|
2
2
|
/** Stable UUID for retries of the same submission; retained for seven days. */
|
|
3
3
|
id: string;
|
|
4
4
|
prompt: string;
|
|
5
|
+
/** Trusted application instructions, separate from the user's request. */
|
|
6
|
+
instructions?: string;
|
|
7
|
+
/** Optional JSON artifact in /workspace; collected only on successful completion. */
|
|
8
|
+
outputFile?: string;
|
|
5
9
|
}
|
|
6
10
|
export interface CodexTask {
|
|
7
11
|
id: string;
|
|
@@ -9,12 +13,15 @@ export interface CodexTask {
|
|
|
9
13
|
startedAt: number;
|
|
10
14
|
finishedAt?: number;
|
|
11
15
|
result?: string;
|
|
16
|
+
artifact?: string;
|
|
12
17
|
error?: string;
|
|
13
18
|
}
|
|
14
19
|
export interface CodexContext {
|
|
15
20
|
start(input: CodexTaskInput): Promise<CodexTask>;
|
|
16
21
|
status(id: string): Promise<CodexTask | null>;
|
|
17
22
|
cancel(id: string): Promise<CodexTask | null>;
|
|
23
|
+
/** Erase the temporary artifact and prevent its later retention. An unstarted ID is fenced. */
|
|
24
|
+
discardArtifact(id: string): Promise<void>;
|
|
18
25
|
}
|
|
19
26
|
export declare function codexInput(op: string, input: any): void;
|
|
20
27
|
export declare function codexContext(call: (op: string, input: unknown) => Promise<any>): CodexContext;
|
package/dist/sdk/codex.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { FlareError, boundedJson } from "./protocol.js";
|
|
2
2
|
export function codexInput(op, input) {
|
|
3
|
-
boundedJson(input,
|
|
4
|
-
if (!input || Array.isArray(input) || !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(input.id) || !["start", "status", "cancel"].includes(op) || Object.keys(input).some((k) => ![
|
|
3
|
+
boundedJson(input, 40000);
|
|
4
|
+
if (!input || Array.isArray(input) || !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(input.id) || !["start", "status", "cancel", "discardArtifact"].includes(op) || Object.keys(input).some((k) => ![
|
|
5
|
+
"id",
|
|
6
|
+
...op === "start" ? ["prompt", "instructions", "outputFile"] : []
|
|
7
|
+
].includes(k)) || op === "start" && (typeof input.prompt !== "string" || !input.prompt.trim() || new TextEncoder().encode(input.prompt).length > 16384 || input.instructions !== undefined && (typeof input.instructions !== "string" || new TextEncoder().encode(input.instructions).length > 16384) || input.outputFile !== undefined && (typeof input.outputFile !== "string" || !/^[a-zA-Z0-9_-]{1,64}\.json$/.test(input.outputFile))))
|
|
5
8
|
throw new FlareError("INVALID_ARGUMENT", "Invalid Codex task");
|
|
6
9
|
}
|
|
7
10
|
export function codexContext(call) {
|
|
@@ -12,6 +15,9 @@ export function codexContext(call) {
|
|
|
12
15
|
return {
|
|
13
16
|
start: (input) => invoke("start", input),
|
|
14
17
|
status: (id) => invoke("status", { id }),
|
|
15
|
-
cancel: (id) => invoke("cancel", { id })
|
|
18
|
+
cancel: (id) => invoke("cancel", { id }),
|
|
19
|
+
discardArtifact: async (id) => {
|
|
20
|
+
await invoke("discardArtifact", { id });
|
|
21
|
+
}
|
|
16
22
|
};
|
|
17
23
|
}
|
package/dist/sdk/search.d.ts
CHANGED
|
@@ -11,7 +11,37 @@ export type SearchHit = {
|
|
|
11
11
|
text: string;
|
|
12
12
|
score: number;
|
|
13
13
|
};
|
|
14
|
+
export type SearchRecord = {
|
|
15
|
+
/** Stable source UUID and monotonically increasing source revision. */
|
|
16
|
+
id: string;
|
|
17
|
+
version: number;
|
|
18
|
+
/** Server-selected access partition; never accept an unchecked client owner. */
|
|
19
|
+
partition: string;
|
|
20
|
+
/** null excludes the record; retain a source tombstone for delayed jobs. */
|
|
21
|
+
text: string | null;
|
|
22
|
+
metadata?: Record<string, string>;
|
|
23
|
+
};
|
|
24
|
+
export type SearchRecordRef = Pick<SearchRecord, "id" | "version">;
|
|
25
|
+
export type SearchRecordState = SearchRecordRef & Omit<SearchState, "fileId">;
|
|
26
|
+
export type SearchRecordHit = SearchRecordRef & {
|
|
27
|
+
text: string;
|
|
28
|
+
score: number;
|
|
29
|
+
};
|
|
30
|
+
export interface SearchRecords {
|
|
31
|
+
/** Schedule from a source mutation's transactional outbox; re-read source in the job. */
|
|
32
|
+
sync(input: SearchRecord): Promise<SearchRecordState>;
|
|
33
|
+
status(input: {
|
|
34
|
+
id: string;
|
|
35
|
+
partition: string;
|
|
36
|
+
}): Promise<SearchRecordState>;
|
|
37
|
+
query(input: {
|
|
38
|
+
query: string;
|
|
39
|
+
partition: string;
|
|
40
|
+
limit?: number;
|
|
41
|
+
}, authorize: (records: SearchRecordRef[]) => Promise<SearchRecordRef[]>): Promise<SearchRecordHit[]>;
|
|
42
|
+
}
|
|
14
43
|
export interface SearchContext {
|
|
44
|
+
readonly records: SearchRecords;
|
|
15
45
|
index(fileId: string): Promise<SearchState>;
|
|
16
46
|
exclude(fileId: string): Promise<SearchState>;
|
|
17
47
|
status(fileId: string): Promise<SearchState>;
|
package/dist/sdk/search.js
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { FlareError } from "./protocol.js";
|
|
2
2
|
export function searchContext(command) {
|
|
3
3
|
return {
|
|
4
|
+
records: {
|
|
5
|
+
sync: (input) => command("record-sync", input),
|
|
6
|
+
status: (input) => command("record-status", input),
|
|
7
|
+
async query(input, authorize) {
|
|
8
|
+
if (typeof authorize !== "function")
|
|
9
|
+
throw new FlareError("FORBIDDEN", "A current source access/version check is required");
|
|
10
|
+
const hits = await command("record-query", input);
|
|
11
|
+
if (!hits.length)
|
|
12
|
+
return [];
|
|
13
|
+
const allowed = await authorize(hits.map(({ id, version }) => ({ id, version })));
|
|
14
|
+
if (!Array.isArray(allowed) || allowed.some((a) => !hits.some((h) => h.id === a.id && h.version === a.version)))
|
|
15
|
+
throw new FlareError("FORBIDDEN", "Invalid source access result");
|
|
16
|
+
const current = await command("record-validate", {
|
|
17
|
+
partition: input.partition,
|
|
18
|
+
records: allowed
|
|
19
|
+
});
|
|
20
|
+
return hits.filter((h) => current.some((a) => a.id === h.id && a.version === h.version));
|
|
21
|
+
}
|
|
22
|
+
},
|
|
4
23
|
index: (fileId) => command("index", { fileId }),
|
|
5
24
|
exclude: (fileId) => command("exclude", { fileId }),
|
|
6
25
|
status: (fileId) => command("status", { fileId }),
|
package/dist/sdk/server.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export type { CodexSubscription } from "./codex-stream.js";
|
|
|
2
2
|
import type { CodexContext } from "./codex.js";
|
|
3
3
|
export type { CodexContext, CodexTask, CodexTaskInput } from "./codex.js";
|
|
4
4
|
import type { SearchContext } from "./search.js";
|
|
5
|
-
export type { SearchContext, SearchHit, SearchState } from "./search.js";
|
|
5
|
+
export type { SearchContext, SearchHit, SearchState, SearchRecord, SearchRecordRef, SearchRecordState, SearchRecordHit, SearchRecords, } from "./search.js";
|
|
6
6
|
export { z } from "zod";
|
|
7
7
|
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
8
8
|
import type { Validator, Schema } from "./schema.js";
|