pi-wasm-kit 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE +11 -0
- package/README.md +206 -2
- package/dist/engine.d.ts +30 -0
- package/dist/engine.js +246 -0
- package/dist/guest/bridge.d.ts +1 -0
- package/dist/guest/bridge.js +14 -0
- package/dist/guest/entry.d.ts +1 -0
- package/dist/guest/entry.js +134 -0
- package/dist/guest/journal.d.ts +6 -0
- package/dist/guest/journal.js +21 -0
- package/dist/guest/platform.d.ts +1 -0
- package/dist/guest/platform.js +64 -0
- package/dist/guest-meta.json +1 -0
- package/dist/guest-source.d.ts +2 -0
- package/dist/guest-source.js +3 -0
- package/dist/guest.js +21929 -0
- package/dist/index.d.ts +104 -0
- package/dist/index.js +84 -0
- package/dist/licenses/@earendil-works__chord__LICENSE +21 -0
- package/dist/licenses/@earendil-works__pi-ai__LICENSE +21 -0
- package/dist/licenses/@earendil-works__pi-durable__LICENSE +21 -0
- package/dist/licenses/@jitl__quickjs-wasmfile-release-sync__LICENSE +47 -0
- package/dist/licenses/abort-controller__LICENSE +21 -0
- package/dist/licenses/event-target-shim__LICENSE +22 -0
- package/dist/licenses/manifest.json +47 -0
- package/dist/licenses/partial-json__LICENSE +21 -0
- package/dist/licenses/quickjs-emscripten-core__LICENSE +21 -0
- package/dist/licenses/typebox__license +23 -0
- package/dist/providers/openai.d.ts +8 -0
- package/dist/providers/openai.js +41 -0
- package/dist/storage/browser.d.ts +2 -0
- package/dist/storage/browser.js +75 -0
- package/dist/storage/node.d.ts +2 -0
- package/dist/storage/node.js +105 -0
- package/dist/types.d.ts +66 -0
- package/dist/types.js +1 -0
- package/package.json +75 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { AgentOptions, AgentConfiguration } from './types.js';
|
|
2
|
+
export type * from './types.js';
|
|
3
|
+
import type { SubmissionDraft, UserInput, ContextView, HarnessInspection, TaskGraph } from '@earendil-works/pi-durable';
|
|
4
|
+
export declare class PiWasmAgent {
|
|
5
|
+
private engine;
|
|
6
|
+
private options;
|
|
7
|
+
readonly conversationId: number;
|
|
8
|
+
private constructor();
|
|
9
|
+
static open(options: AgentOptions): Promise<PiWasmAgent>;
|
|
10
|
+
/** Start scheduling after opening with autoResume: false. */
|
|
11
|
+
resume(): Promise<void>;
|
|
12
|
+
submit(content: UserInput, requestId?: `${string}-${string}-${string}-${string}-${string}`, options?: {
|
|
13
|
+
conversationId?: number;
|
|
14
|
+
whenBusy?: 'steer' | 'followUp' | 'reject';
|
|
15
|
+
}): Promise<{
|
|
16
|
+
id: number;
|
|
17
|
+
}>;
|
|
18
|
+
submitDraft(submission: SubmissionDraft, conversationId?: number): Promise<{
|
|
19
|
+
id: number;
|
|
20
|
+
}>;
|
|
21
|
+
wait(id: number): Promise<({
|
|
22
|
+
readonly id: import("@earendil-works/pi-durable").SubmissionId;
|
|
23
|
+
readonly conversationId: import("@earendil-works/pi-durable").ConversationId;
|
|
24
|
+
readonly requestId?: string;
|
|
25
|
+
} & {
|
|
26
|
+
readonly type: "input";
|
|
27
|
+
} & {
|
|
28
|
+
readonly status: "done";
|
|
29
|
+
readonly entry: import("@earendil-works/pi-durable").EntryId;
|
|
30
|
+
readonly answer: import("@earendil-works/pi-durable").EntryId;
|
|
31
|
+
readonly reason?: never;
|
|
32
|
+
readonly detail?: never;
|
|
33
|
+
} & {
|
|
34
|
+
readonly status: "done" | "unanswered";
|
|
35
|
+
}) | ({
|
|
36
|
+
readonly id: import("@earendil-works/pi-durable").SubmissionId;
|
|
37
|
+
readonly conversationId: import("@earendil-works/pi-durable").ConversationId;
|
|
38
|
+
readonly requestId?: string;
|
|
39
|
+
} & {
|
|
40
|
+
readonly type: "input";
|
|
41
|
+
} & {
|
|
42
|
+
readonly status: "unanswered";
|
|
43
|
+
readonly entry?: import("@earendil-works/pi-durable").EntryId;
|
|
44
|
+
readonly answer?: never;
|
|
45
|
+
readonly reason: string;
|
|
46
|
+
readonly detail?: import("@earendil-works/chord").JsonValue;
|
|
47
|
+
} & {
|
|
48
|
+
readonly status: "done" | "unanswered";
|
|
49
|
+
}) | ({
|
|
50
|
+
readonly id: import("@earendil-works/pi-durable").SubmissionId;
|
|
51
|
+
readonly conversationId: import("@earendil-works/pi-durable").ConversationId;
|
|
52
|
+
readonly requestId?: string;
|
|
53
|
+
} & {
|
|
54
|
+
readonly type: "write";
|
|
55
|
+
} & {
|
|
56
|
+
readonly status: "done";
|
|
57
|
+
readonly entry: import("@earendil-works/pi-durable").EntryId;
|
|
58
|
+
readonly answer?: never;
|
|
59
|
+
readonly reason?: never;
|
|
60
|
+
readonly detail?: never;
|
|
61
|
+
} & {
|
|
62
|
+
readonly status: "done" | "unanswered";
|
|
63
|
+
}) | ({
|
|
64
|
+
readonly id: import("@earendil-works/pi-durable").SubmissionId;
|
|
65
|
+
readonly conversationId: import("@earendil-works/pi-durable").ConversationId;
|
|
66
|
+
readonly requestId?: string;
|
|
67
|
+
} & {
|
|
68
|
+
readonly type: "write";
|
|
69
|
+
} & {
|
|
70
|
+
readonly status: "unanswered";
|
|
71
|
+
readonly entry?: never;
|
|
72
|
+
readonly answer?: never;
|
|
73
|
+
readonly reason: string;
|
|
74
|
+
readonly detail?: import("@earendil-works/chord").JsonValue;
|
|
75
|
+
} & {
|
|
76
|
+
readonly status: "done" | "unanswered";
|
|
77
|
+
})>;
|
|
78
|
+
view(conversationId?: number): Promise<import("@earendil-works/pi-durable").ConversationView>;
|
|
79
|
+
context(conversationId?: number, at?: number): Promise<ContextView>;
|
|
80
|
+
configure(change: AgentConfiguration, conversationId?: number): Promise<void>;
|
|
81
|
+
createConversation(agent?: Omit<AgentConfiguration, 'extensions' | 'tools'>): Promise<{
|
|
82
|
+
conversationId: number;
|
|
83
|
+
}>;
|
|
84
|
+
fork(at: number, conversationId?: number): Promise<{
|
|
85
|
+
conversationId: number;
|
|
86
|
+
}>;
|
|
87
|
+
reset(handoff?: string, conversationId?: number): Promise<void>;
|
|
88
|
+
compact(instructions?: string, conversationId?: number): Promise<{
|
|
89
|
+
taskId: number;
|
|
90
|
+
}>;
|
|
91
|
+
waitForTask(id: number): Promise<any>;
|
|
92
|
+
inspect(): Promise<HarnessInspection>;
|
|
93
|
+
taskGraph(): Promise<TaskGraph>;
|
|
94
|
+
abort(conversationId?: number, background?: boolean): Promise<void>;
|
|
95
|
+
abortSubmission(id: number): Promise<string>;
|
|
96
|
+
watch(conversationId?: number): Promise<void>;
|
|
97
|
+
install(source: string): Promise<string>;
|
|
98
|
+
uninstall(name: string): Promise<void>;
|
|
99
|
+
/** Trusted application code inside WASM. Arguments/results must be JSON serializable. */
|
|
100
|
+
evaluate<T = unknown>(source: string, args?: unknown, conversationId?: number): Promise<T>;
|
|
101
|
+
close(): Promise<void>;
|
|
102
|
+
/** Abrupt shutdown: unfinished work stays persisted and resumes on next open. */
|
|
103
|
+
terminate(): Promise<void>;
|
|
104
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Engine } from './engine.js';
|
|
2
|
+
export class PiWasmAgent {
|
|
3
|
+
engine;
|
|
4
|
+
options;
|
|
5
|
+
conversationId;
|
|
6
|
+
constructor(engine, options, conversationId) {
|
|
7
|
+
this.engine = engine;
|
|
8
|
+
this.options = options;
|
|
9
|
+
this.conversationId = conversationId;
|
|
10
|
+
}
|
|
11
|
+
static async open(options) {
|
|
12
|
+
let engine;
|
|
13
|
+
try {
|
|
14
|
+
const names = new Set();
|
|
15
|
+
for (const tool of options.tools ?? []) {
|
|
16
|
+
if (names.has(tool.name))
|
|
17
|
+
throw new Error(`Duplicate tool: ${tool.name}`);
|
|
18
|
+
names.add(tool.name);
|
|
19
|
+
}
|
|
20
|
+
const emit = (event) => { try {
|
|
21
|
+
options.onEvent?.(event);
|
|
22
|
+
}
|
|
23
|
+
catch { /* Observers cannot affect commits. */ } };
|
|
24
|
+
engine = await Engine.create(async (method, data, signal, update) => {
|
|
25
|
+
if (signal.aborted)
|
|
26
|
+
throw new Error('Runtime terminated');
|
|
27
|
+
switch (method) {
|
|
28
|
+
case 'load': return options.journal.load();
|
|
29
|
+
case 'append':
|
|
30
|
+
await options.journal.append(data);
|
|
31
|
+
emit({ type: 'commit', seq: data.seq });
|
|
32
|
+
return null;
|
|
33
|
+
case 'model': return options.model(data, signal, update);
|
|
34
|
+
case 'tool': {
|
|
35
|
+
const tool = options.tools?.find(tool => tool.name === data.name);
|
|
36
|
+
if (!tool)
|
|
37
|
+
throw new Error(`Tool not granted: ${data.name}`);
|
|
38
|
+
return tool.execute(data.args, { taskId: data.taskId, conversationId: data.conversationId, callId: data.callId, signal, output: text => update({ type: 'output', text }) });
|
|
39
|
+
}
|
|
40
|
+
default: throw new Error(`Capability not granted: ${method}`);
|
|
41
|
+
}
|
|
42
|
+
}, emit, options.cpuSliceMs, options.memoryLimitBytes);
|
|
43
|
+
const opened = await engine.call('open', { tools: (options.tools ?? []).map(({ execute, ...definition }) => definition), instructions: options.instructions, modelId: options.modelId, contextWindow: options.contextWindow, extensions: options.extensions, settings: options.settings, events: !!options.onEvent, autoResume: options.autoResume });
|
|
44
|
+
return new PiWasmAgent(engine, options, opened.conversationId);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
await engine?.dispose();
|
|
48
|
+
await options.journal.close();
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Start scheduling after opening with autoResume: false. */
|
|
53
|
+
resume() { return this.engine.call('resume', {}); }
|
|
54
|
+
submit(content, requestId = crypto.randomUUID(), options = {}) {
|
|
55
|
+
return this.submitDraft({ type: 'input', content, requestId, whenBusy: options.whenBusy }, options.conversationId);
|
|
56
|
+
}
|
|
57
|
+
submitDraft(submission, conversationId) { return this.engine.call('submit', { submission, conversationId }); }
|
|
58
|
+
wait(id) { return this.engine.call('wait', { id }); }
|
|
59
|
+
view(conversationId) { return this.engine.call('view', { conversationId }); }
|
|
60
|
+
context(conversationId, at) { return this.engine.call('context', { conversationId, at }); }
|
|
61
|
+
configure(change, conversationId) { return this.engine.call('configure', { change, conversationId }); }
|
|
62
|
+
createConversation(agent) { return this.engine.call('createConversation', { agent }); }
|
|
63
|
+
fork(at, conversationId) { return this.engine.call('fork', { at, conversationId }); }
|
|
64
|
+
reset(handoff, conversationId) { return this.engine.call('reset', { handoff, conversationId }); }
|
|
65
|
+
compact(instructions, conversationId) { return this.engine.call('compact', { instructions, conversationId }); }
|
|
66
|
+
waitForTask(id) { return this.engine.call('waitForTask', { id }); }
|
|
67
|
+
inspect() { return this.engine.call('inspect'); }
|
|
68
|
+
taskGraph() { return this.engine.call('taskGraph'); }
|
|
69
|
+
abort(conversationId, background = false) { return this.engine.call('abort', { conversationId, background }); }
|
|
70
|
+
abortSubmission(id) { return this.engine.call('abortSubmission', { id }); }
|
|
71
|
+
watch(conversationId) { return this.engine.call('watch', { conversationId }); }
|
|
72
|
+
install(source) { return this.engine.call('install', { source }); }
|
|
73
|
+
uninstall(name) { return this.engine.call('uninstall', { name }); }
|
|
74
|
+
/** Trusted application code inside WASM. Arguments/results must be JSON serializable. */
|
|
75
|
+
evaluate(source, args = null, conversationId) { return this.engine.call('evaluate', { source, args, conversationId }); }
|
|
76
|
+
async close() { try {
|
|
77
|
+
await this.engine.call('close');
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
await this.terminate();
|
|
81
|
+
} }
|
|
82
|
+
/** Abrupt shutdown: unfinished work stays persisted and resumes on next open. */
|
|
83
|
+
async terminate() { await this.engine.dispose(); await this.options.journal.close(); }
|
|
84
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Mario Zechner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Mario Zechner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Mario Zechner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
quickjs-emscripten:
|
|
2
|
+
The MIT License
|
|
3
|
+
|
|
4
|
+
quickjs-emscripten copyright (c) 2019-2024 Jake Teton-Landis
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
quickjs:
|
|
26
|
+
QuickJS Javascript Engine
|
|
27
|
+
|
|
28
|
+
Copyright (c) 2017-2021 Fabrice Bellard
|
|
29
|
+
Copyright (c) 2017-2021 Charlie Gordon
|
|
30
|
+
|
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
32
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
33
|
+
in the Software without restriction, including without limitation the rights
|
|
34
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
35
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
36
|
+
furnished to do so, subject to the following conditions:
|
|
37
|
+
|
|
38
|
+
The above copyright notice and this permission notice shall be included in
|
|
39
|
+
all copies or substantial portions of the Software.
|
|
40
|
+
|
|
41
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
42
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
43
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
44
|
+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
45
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
46
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
47
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Toru Nagashima
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 Toru Nagashima
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "@earendil-works/chord",
|
|
4
|
+
"version": "1.1.0",
|
|
5
|
+
"license": "MIT"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"name": "@earendil-works/pi-ai",
|
|
9
|
+
"version": "1.1.0",
|
|
10
|
+
"license": "MIT"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "@earendil-works/pi-durable",
|
|
14
|
+
"version": "1.1.0",
|
|
15
|
+
"license": "MIT"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "@jitl/quickjs-wasmfile-release-sync",
|
|
19
|
+
"version": "0.32.0",
|
|
20
|
+
"license": "MIT"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "abort-controller",
|
|
24
|
+
"version": "3.0.0",
|
|
25
|
+
"license": "MIT"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "event-target-shim",
|
|
29
|
+
"version": "5.0.1",
|
|
30
|
+
"license": "MIT"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "partial-json",
|
|
34
|
+
"version": "0.1.7",
|
|
35
|
+
"license": "MIT"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "quickjs-emscripten-core",
|
|
39
|
+
"version": "0.32.0",
|
|
40
|
+
"license": "MIT"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "typebox",
|
|
44
|
+
"version": "1.3.27",
|
|
45
|
+
"license": "MIT"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Promplate Dev Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
quickjs-emscripten copyright (c) 2019-2024 Jake Teton-Landis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
TypeBox
|
|
2
|
+
|
|
3
|
+
The MIT License (MIT)
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2017-2026 Haydn Paterson
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in
|
|
15
|
+
all copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ModelHandler } from '../types.js';
|
|
2
|
+
/** OpenAI Chat Completions-compatible transport. Credentials never enter WASM. */
|
|
3
|
+
export declare function openAICompatible(options: {
|
|
4
|
+
baseURL: string;
|
|
5
|
+
model: string;
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
}): ModelHandler;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getSystemMessageText } from '@earendil-works/pi-ai/utils/text';
|
|
2
|
+
import { getCurrentTools } from '@earendil-works/pi-ai/utils/transcript';
|
|
3
|
+
/** OpenAI Chat Completions-compatible transport. Credentials never enter WASM. */
|
|
4
|
+
export function openAICompatible(options) {
|
|
5
|
+
return async ({ context }, signal) => {
|
|
6
|
+
const messages = context.messages.map((message) => {
|
|
7
|
+
if (message.role === 'system')
|
|
8
|
+
return { role: 'system', content: getSystemMessageText(message) };
|
|
9
|
+
if (message.role === 'user')
|
|
10
|
+
return { role: 'user', content: typeof message.content === 'string' ? message.content : message.content.map((x) => { if (x.type === 'text')
|
|
11
|
+
return { type: 'text', text: x.text }; if (x.type === 'image')
|
|
12
|
+
return { type: 'image_url', image_url: { url: `data:${x.mimeType};base64,${x.data}` } }; throw new Error(`Unsupported user content: ${x.type}`); }) };
|
|
13
|
+
if (message.role === 'toolResult') {
|
|
14
|
+
if (message.content.some((x) => x.type !== 'text'))
|
|
15
|
+
throw new Error('HTTP adapter supports text tool results only');
|
|
16
|
+
return { role: 'tool', tool_call_id: message.toolCallId, content: message.content.filter((x) => x.type === 'text').map((x) => x.text).join('\n') };
|
|
17
|
+
}
|
|
18
|
+
const text = message.content.filter((x) => x.type === 'text').map((x) => x.text).join('');
|
|
19
|
+
const calls = message.content.filter((x) => x.type === 'toolCall').map((x) => ({ id: x.id, type: 'function', function: { name: x.name, arguments: JSON.stringify(x.arguments) } }));
|
|
20
|
+
return { role: 'assistant', content: text || null, ...(calls.length ? { tool_calls: calls } : {}) };
|
|
21
|
+
});
|
|
22
|
+
const tools = getCurrentTools(context.messages).map(tool => ({ type: 'function', function: { name: tool.name, description: tool.description, parameters: tool.parameters } }));
|
|
23
|
+
const response = await fetch(`${options.baseURL.replace(/\/$/, '')}/chat/completions`, {
|
|
24
|
+
method: 'POST', headers: { 'Content-Type': 'application/json', ...(options.apiKey ? { Authorization: `Bearer ${options.apiKey}` } : {}) },
|
|
25
|
+
body: JSON.stringify({ model: options.model, messages, ...(tools.length ? { tools } : {}), stream: false }),
|
|
26
|
+
signal: AbortSignal.any([signal, AbortSignal.timeout(options.timeoutMs ?? 60000)]),
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok)
|
|
29
|
+
throw new Error(`Model request failed: HTTP ${response.status}`);
|
|
30
|
+
const data = await response.json();
|
|
31
|
+
const choice = data.choices?.[0];
|
|
32
|
+
if (!choice?.message)
|
|
33
|
+
throw new Error('Model returned no assistant message');
|
|
34
|
+
const content = [];
|
|
35
|
+
if (choice.message.content)
|
|
36
|
+
content.push({ type: 'text', text: choice.message.content });
|
|
37
|
+
for (const call of choice.message.tool_calls ?? [])
|
|
38
|
+
content.push({ type: 'toolCall', id: call.id, name: call.function.name, arguments: JSON.parse(call.function.arguments) });
|
|
39
|
+
return { role: 'assistant', content, api: 'host', provider: 'host', model: options.model, stopReason: content.some(x => x.type === 'toolCall') ? 'toolUse' : choice.finish_reason === 'length' ? 'length' : 'stop', usage: { input: data.usage?.prompt_tokens ?? 0, output: data.usage?.completion_tokens ?? 0, totalTokens: data.usage?.total_tokens ?? 0, cacheRead: 0, cacheWrite: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } }, timestamp: Date.now() };
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export async function openBrowserJournal(name) {
|
|
2
|
+
if (!globalThis.navigator?.locks)
|
|
3
|
+
throw new Error('Web Locks requires a secure browser context (HTTPS or localhost)');
|
|
4
|
+
let unlock;
|
|
5
|
+
let acquired;
|
|
6
|
+
let denied;
|
|
7
|
+
const ready = new Promise((resolve, reject) => { acquired = resolve; denied = reject; });
|
|
8
|
+
const lock = navigator.locks.request(`pi-wasm-kit:${name}`, { ifAvailable: true }, async (token) => {
|
|
9
|
+
if (!token) {
|
|
10
|
+
denied(new Error('This journal is already open in another tab'));
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
await new Promise(resolve => { unlock = resolve; acquired(); });
|
|
14
|
+
});
|
|
15
|
+
void lock.catch(denied);
|
|
16
|
+
await ready;
|
|
17
|
+
let db;
|
|
18
|
+
try {
|
|
19
|
+
db = await new Promise((resolve, reject) => {
|
|
20
|
+
const request = indexedDB.open(`pi-wasm-kit:${name}`, 1);
|
|
21
|
+
request.onupgradeneeded = () => request.result.createObjectStore('commits', { keyPath: 'seq' });
|
|
22
|
+
request.onsuccess = () => resolve(request.result);
|
|
23
|
+
request.onerror = () => reject(request.error);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
unlock();
|
|
28
|
+
await lock;
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
let closed = false;
|
|
32
|
+
let tail = Promise.resolve();
|
|
33
|
+
return {
|
|
34
|
+
async load() {
|
|
35
|
+
if (closed)
|
|
36
|
+
throw new Error('Journal is closed');
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const tx = db.transaction('commits', 'readonly');
|
|
39
|
+
const request = tx.objectStore('commits').getAll();
|
|
40
|
+
tx.oncomplete = () => resolve(request.result);
|
|
41
|
+
tx.onabort = () => reject(tx.error ?? new Error('Journal read aborted'));
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
append(commit) {
|
|
45
|
+
if (closed)
|
|
46
|
+
return Promise.reject(new Error('Journal is closed'));
|
|
47
|
+
const snapshot = structuredClone(commit);
|
|
48
|
+
const write = tail.then(() => new Promise((resolve, reject) => {
|
|
49
|
+
const tx = db.transaction('commits', 'readwrite', { durability: 'strict' });
|
|
50
|
+
const store = tx.objectStore('commits');
|
|
51
|
+
const count = store.count();
|
|
52
|
+
count.onsuccess = () => {
|
|
53
|
+
if (snapshot.seq !== count.result + 1) {
|
|
54
|
+
tx.abort();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
store.add(snapshot);
|
|
58
|
+
};
|
|
59
|
+
tx.oncomplete = () => resolve();
|
|
60
|
+
tx.onabort = () => reject(tx.error ?? new Error('Journal sequence conflict'));
|
|
61
|
+
}));
|
|
62
|
+
tail = write;
|
|
63
|
+
return write;
|
|
64
|
+
},
|
|
65
|
+
async close() { if (closed)
|
|
66
|
+
return; closed = true; try {
|
|
67
|
+
await tail;
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
db.close();
|
|
71
|
+
unlock();
|
|
72
|
+
await lock;
|
|
73
|
+
} },
|
|
74
|
+
};
|
|
75
|
+
}
|