@pi-oxide/pi-host-web 0.3.1 → 0.4.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/package.json +35 -4
- package/pi_host_web.d.ts +97 -202
- package/pi_host_web.js +218 -109
- package/pi_host_web_bg.wasm +0 -0
- package/sdk/agent.ts +274 -0
- package/sdk/artifacts.ts +35 -0
- package/sdk/context.ts +4 -0
- package/sdk/errors.ts +24 -0
- package/sdk/events.ts +52 -0
- package/sdk/index.d.ts +17 -43
- package/sdk/index.js +86 -220
- package/sdk/index.ts +53 -0
- package/sdk/init.ts +58 -0
- package/sdk/internal/engine.ts +614 -0
- package/sdk/internal/events.ts +241 -0
- package/sdk/internal/providers/anthropic.ts +440 -0
- package/sdk/internal/providers/openai.ts +177 -0
- package/sdk/internal/providers/types.ts +64 -0
- package/sdk/internal/stores/indexedDb.ts +24 -0
- package/sdk/internal/stores/persistence.ts +71 -0
- package/sdk/internal/tools/artifact.ts +24 -0
- package/sdk/internal/tools/browser.ts +449 -0
- package/sdk/internal/tools/browserRuntime.ts +48 -0
- package/sdk/internal/tools/liveRuntime.ts +151 -0
- package/sdk/internal/tools/registry.ts +174 -0
- package/sdk/internal/tools/service.ts +157 -0
- package/sdk/model.ts +35 -0
- package/sdk/react/index.ts +1 -0
- package/sdk/react/useAgent.ts +334 -0
- package/sdk/snapshot.ts +25 -0
- package/sdk/stores.ts +72 -0
- package/sdk/tools.ts +47 -0
- package/sdk/types.ts +252 -0
package/sdk/index.js
CHANGED
|
@@ -1,245 +1,111 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* High-level JS SDK for @pi-oxide/pi-host-web.
|
|
3
3
|
*
|
|
4
|
-
* Hides WASM loading
|
|
4
|
+
* Hides WASM loading and numeric handles.
|
|
5
5
|
* Supports streaming LLM responses and full agent lifecycle.
|
|
6
6
|
*
|
|
7
7
|
* Import from the package root:
|
|
8
|
-
* import {
|
|
8
|
+
* import { ensureInit, toolResult } from "@pi-oxide/pi-host-web";
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
12
|
+
default as init,
|
|
13
|
+
initSync,
|
|
14
|
+
createHostAgent,
|
|
15
|
+
destroyHostAgent,
|
|
16
|
+
startTurn,
|
|
17
|
+
hostFeedLlmChunk,
|
|
18
|
+
hostLlmDone,
|
|
19
|
+
hostToolDone,
|
|
20
|
+
hostAcceptCompaction,
|
|
21
|
+
hostContinueTurn,
|
|
22
|
+
getHostStatePersistData,
|
|
23
|
+
restoreHostState,
|
|
24
|
+
restoreHostStateFromJson,
|
|
25
|
+
hostReadArtifact,
|
|
26
|
+
hostSearchArtifacts,
|
|
27
|
+
hostToolCancelled,
|
|
28
|
+
hostAbort,
|
|
29
|
+
getHostAgentPersistData,
|
|
30
|
+
restoreHostAgent,
|
|
31
|
+
createHostState,
|
|
32
|
+
destroyHostState,
|
|
33
|
+
hostSteer,
|
|
34
|
+
hostReset,
|
|
35
|
+
estimateTokens,
|
|
36
|
+
estimateTokensForText,
|
|
37
|
+
setLogLevel,
|
|
31
38
|
} from "../pi_host_web.js";
|
|
32
39
|
|
|
33
|
-
export {
|
|
40
|
+
export {
|
|
41
|
+
createHostState,
|
|
42
|
+
destroyHostState,
|
|
43
|
+
createHostAgent,
|
|
44
|
+
destroyHostAgent,
|
|
45
|
+
startTurn,
|
|
46
|
+
hostFeedLlmChunk,
|
|
47
|
+
hostLlmDone,
|
|
48
|
+
hostToolDone,
|
|
49
|
+
hostAcceptCompaction,
|
|
50
|
+
hostContinueTurn,
|
|
51
|
+
getHostStatePersistData,
|
|
52
|
+
restoreHostState,
|
|
53
|
+
restoreHostStateFromJson,
|
|
54
|
+
hostReadArtifact,
|
|
55
|
+
hostSearchArtifacts,
|
|
56
|
+
hostToolCancelled,
|
|
57
|
+
hostAbort,
|
|
58
|
+
getHostAgentPersistData,
|
|
59
|
+
restoreHostAgent,
|
|
60
|
+
hostSteer,
|
|
61
|
+
hostReset,
|
|
62
|
+
estimateTokens,
|
|
63
|
+
estimateTokensForText,
|
|
64
|
+
setLogLevel,
|
|
65
|
+
};
|
|
34
66
|
|
|
35
67
|
let initialized = false;
|
|
36
68
|
|
|
37
69
|
/** Ensure the WASM module is loaded. Safe to call multiple times. */
|
|
38
70
|
export async function ensureInit() {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
71
|
+
if (initialized) return;
|
|
72
|
+
if (typeof process !== "undefined" && process.versions?.node) {
|
|
73
|
+
const { readFileSync } = await import("node:fs");
|
|
74
|
+
const bytes = readFileSync(
|
|
75
|
+
new URL("../pi_host_web_bg.wasm", import.meta.url),
|
|
76
|
+
);
|
|
77
|
+
initSync({ module: bytes });
|
|
78
|
+
} else {
|
|
79
|
+
await init();
|
|
80
|
+
}
|
|
81
|
+
initialized = true;
|
|
50
82
|
}
|
|
51
83
|
|
|
52
|
-
class HostError extends Error {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
84
|
+
export class HostError extends Error {
|
|
85
|
+
constructor(code, message) {
|
|
86
|
+
super(message);
|
|
87
|
+
this.code = code;
|
|
88
|
+
this.name = "HostError";
|
|
89
|
+
}
|
|
58
90
|
}
|
|
59
91
|
|
|
60
|
-
function unwrap(result) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
92
|
+
export function unwrap(result) {
|
|
93
|
+
if (!result.ok) {
|
|
94
|
+
throw new HostError(result.error.code, result.error.message);
|
|
95
|
+
}
|
|
96
|
+
return result.data;
|
|
65
97
|
}
|
|
66
98
|
|
|
67
99
|
/** Build a successful tool result payload. */
|
|
68
100
|
export function toolResult(text, opts = {}) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
export function toolError(code, message) {
|
|
80
|
-
return { error: { code, message } };
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* High-level agent that manages the WASM handle and drive-loop.
|
|
85
|
-
*
|
|
86
|
-
* Usage:
|
|
87
|
-
* const agent = await Agent.create(options);
|
|
88
|
-
* const finalAction = await agent.run("hello", { llm, tools, onEvent });
|
|
89
|
-
* agent.destroy();
|
|
90
|
-
*/
|
|
91
|
-
export class Agent {
|
|
92
|
-
/** @type {number} */
|
|
93
|
-
#handle;
|
|
94
|
-
|
|
95
|
-
constructor(handle) {
|
|
96
|
-
this.#handle = handle;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/** Create a new agent. Loads WASM on first call automatically. */
|
|
100
|
-
static async create(options) {
|
|
101
|
-
await ensureInit();
|
|
102
|
-
const result = unwrap(createAgent(options));
|
|
103
|
-
return new Agent(result.handle);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Run one user prompt through the full turn loop.
|
|
108
|
-
*
|
|
109
|
-
* @param {string} promptText
|
|
110
|
-
* @param {object} config
|
|
111
|
-
* @param {LlmProvider} config.llm
|
|
112
|
-
* @param {Record<string, (call: ToolCall) => Promise<ToolResult> | ToolResult>} config.tools
|
|
113
|
-
* @param {(event: AgentEvent) => void} [config.onEvent]
|
|
114
|
-
* @param {AbortSignal} [config.signal] — abort to stop mid-stream or mid-tool
|
|
115
|
-
* @returns {Promise<AgentAction>} terminal action (finished or wait_for_input)
|
|
116
|
-
*/
|
|
117
|
-
async run(promptText, config) {
|
|
118
|
-
const signal = config.signal;
|
|
119
|
-
const checkAbort = () => {
|
|
120
|
-
if (signal?.aborted) {
|
|
121
|
-
this.stop();
|
|
122
|
-
throw new HostError("user_aborted", "Turn stopped by user");
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
let step = unwrap(prompt(this.#handle, { text: promptText }));
|
|
127
|
-
for (const event of step.events) {
|
|
128
|
-
config.onEvent?.(event);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
while (true) {
|
|
132
|
-
checkAbort();
|
|
133
|
-
let actions = step.actions ?? [];
|
|
134
|
-
if (actions.length === 0) {
|
|
135
|
-
return { type: "finished", messages: [] };
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
for (const action of actions) {
|
|
139
|
-
checkAbort();
|
|
140
|
-
switch (action.type) {
|
|
141
|
-
case "stream_llm": {
|
|
142
|
-
const stream = await config.llm.call(action.context, signal);
|
|
143
|
-
for await (const chunk of stream.chunks) {
|
|
144
|
-
checkAbort();
|
|
145
|
-
const ev = unwrap(feedLlmChunk(this.#handle, chunk));
|
|
146
|
-
for (const e of ev.events) config.onEvent?.(e);
|
|
147
|
-
}
|
|
148
|
-
checkAbort();
|
|
149
|
-
const result = await stream.result;
|
|
150
|
-
step = unwrap(onLlmDone(this.#handle, result));
|
|
151
|
-
for (const e of step.events) config.onEvent?.(e);
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
case "execute_tools": {
|
|
156
|
-
for (const call of action.calls) {
|
|
157
|
-
checkAbort();
|
|
158
|
-
const started = unwrap(onToolStarted(this.#handle, call.id));
|
|
159
|
-
for (const e of started.events) config.onEvent?.(e);
|
|
160
|
-
|
|
161
|
-
const handler = config.tools[call.name];
|
|
162
|
-
let result;
|
|
163
|
-
if (handler) {
|
|
164
|
-
result = await handler(call);
|
|
165
|
-
} else {
|
|
166
|
-
result = toolError("unknown_tool", `No handler for ${call.name}`);
|
|
167
|
-
}
|
|
168
|
-
step = unwrap(onToolDone(this.#handle, call.id, result));
|
|
169
|
-
for (const e of step.events) config.onEvent?.(e);
|
|
170
|
-
}
|
|
171
|
-
if ((step.actions ?? []).length === 0) {
|
|
172
|
-
step = unwrap(continueTurn(this.#handle));
|
|
173
|
-
for (const e of step.events) config.onEvent?.(e);
|
|
174
|
-
}
|
|
175
|
-
break;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
case "cancel_tools": {
|
|
179
|
-
for (const id of action.tool_call_ids) {
|
|
180
|
-
step = unwrap(
|
|
181
|
-
onToolCancelled(this.#handle, id, action.reason)
|
|
182
|
-
);
|
|
183
|
-
for (const e of step.events) config.onEvent?.(e);
|
|
184
|
-
}
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
case "finished":
|
|
189
|
-
return action;
|
|
190
|
-
|
|
191
|
-
case "wait_for_input":
|
|
192
|
-
return action;
|
|
193
|
-
|
|
194
|
-
default:
|
|
195
|
-
return action;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/** Abort a running turn mid-stream or mid-tool. */
|
|
202
|
-
stop() {
|
|
203
|
-
try {
|
|
204
|
-
unwrap(abort(this.#handle));
|
|
205
|
-
} catch (e) {
|
|
206
|
-
if (e.code !== "wrong_phase") throw e;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/** Reset agent state (clear messages, return to idle). */
|
|
211
|
-
reset() {
|
|
212
|
-
unwrap(reset(this.#handle));
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/** Get public agent state. */
|
|
216
|
-
state() {
|
|
217
|
-
return unwrap(state(this.#handle));
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/** Get session state for persistence. */
|
|
221
|
-
getSessionState() {
|
|
222
|
-
return unwrap(getSessionState(this.#handle));
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/** Set session state (e.g. after restoring from storage). */
|
|
226
|
-
setSessionState(sessionState) {
|
|
227
|
-
unwrap(setSessionState(this.#handle, sessionState));
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/** Send a steering message mid-turn. */
|
|
231
|
-
steer(message) {
|
|
232
|
-
const out = unwrap(steer(this.#handle, message));
|
|
233
|
-
return out.events;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/** Queue a follow-up message. */
|
|
237
|
-
followUp(message) {
|
|
238
|
-
unwrap(followUp(this.#handle, message));
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/** Destroy the underlying WASM handle. */
|
|
242
|
-
destroy() {
|
|
243
|
-
destroyAgent(this.#handle);
|
|
244
|
-
}
|
|
101
|
+
const payload = {
|
|
102
|
+
content: [{ type: "text", text }],
|
|
103
|
+
};
|
|
104
|
+
if (opts.terminate) {
|
|
105
|
+
payload.terminate = true;
|
|
106
|
+
}
|
|
107
|
+
if (opts.details) {
|
|
108
|
+
payload.details = opts.details;
|
|
109
|
+
}
|
|
110
|
+
return payload;
|
|
245
111
|
}
|
package/sdk/index.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Public SDK exports — the only surface normal apps should import.
|
|
2
|
+
// Internal engine details are hidden in sdk/internal/.
|
|
3
|
+
|
|
4
|
+
export { ensureInit, HostError, unwrap, toolResult } from "./init.ts";
|
|
5
|
+
|
|
6
|
+
// SDK exports
|
|
7
|
+
export { Agent } from "./agent.ts";
|
|
8
|
+
export { defineModel } from "./model.ts";
|
|
9
|
+
export { anthropic } from "./internal/providers/anthropic.ts";
|
|
10
|
+
export { openai, openaiCompatible } from "./internal/providers/openai.ts";
|
|
11
|
+
export { defineTools, tool } from "./tools.ts";
|
|
12
|
+
export { browserTools } from "./internal/tools/browser.ts";
|
|
13
|
+
export { artifactTools } from "./internal/tools/artifact.ts";
|
|
14
|
+
export { indexedDbStore, memoryStore, localStorageStore, httpStore } from "./stores.ts";
|
|
15
|
+
export { useAgent } from "./react/index.ts";
|
|
16
|
+
|
|
17
|
+
export type {
|
|
18
|
+
AgentArtifact,
|
|
19
|
+
AgentArtifactRef,
|
|
20
|
+
ArtifactPolicy,
|
|
21
|
+
ArtifactSearchQuery,
|
|
22
|
+
ArtifactSearchResult,
|
|
23
|
+
} from "./artifacts.ts";
|
|
24
|
+
|
|
25
|
+
export type {
|
|
26
|
+
AgentConfig,
|
|
27
|
+
AgentInput,
|
|
28
|
+
AgentRunOptions,
|
|
29
|
+
AgentRunResult,
|
|
30
|
+
AgentEventName,
|
|
31
|
+
AgentEventHandler,
|
|
32
|
+
AgentMessage,
|
|
33
|
+
AgentContentBlock,
|
|
34
|
+
AgentToolRun,
|
|
35
|
+
AgentStatus,
|
|
36
|
+
AgentModel,
|
|
37
|
+
ModelRequest,
|
|
38
|
+
ModelResponse,
|
|
39
|
+
ModelEvent,
|
|
40
|
+
AgentTools,
|
|
41
|
+
AgentToolDefinition,
|
|
42
|
+
AgentStore,
|
|
43
|
+
AgentSnapshot,
|
|
44
|
+
AgentContextPolicy,
|
|
45
|
+
AgentSummarizer,
|
|
46
|
+
AgentTelemetry,
|
|
47
|
+
AgentError,
|
|
48
|
+
Unsubscribe,
|
|
49
|
+
TokenUsage,
|
|
50
|
+
UseAgentResult,
|
|
51
|
+
} from "./types.ts";
|
|
52
|
+
|
|
53
|
+
export { createAgentError } from "./errors.ts";
|
package/sdk/init.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// WASM initialization and low-level helpers.
|
|
2
|
+
// Kept separate from index.ts to avoid circular imports with internal modules.
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
default as init,
|
|
6
|
+
initSync,
|
|
7
|
+
} from "../pi_host_web.js";
|
|
8
|
+
|
|
9
|
+
let initialized = false;
|
|
10
|
+
|
|
11
|
+
/** Ensure the WASM module is loaded. Safe to call multiple times. */
|
|
12
|
+
export async function ensureInit() {
|
|
13
|
+
if (initialized) return;
|
|
14
|
+
if (typeof process !== "undefined" && process.versions?.node) {
|
|
15
|
+
const { readFileSync } = await import("node:fs");
|
|
16
|
+
const bytes = readFileSync(
|
|
17
|
+
new URL("../pi_host_web_bg.wasm", import.meta.url),
|
|
18
|
+
);
|
|
19
|
+
initSync({ module: bytes });
|
|
20
|
+
} else {
|
|
21
|
+
await init();
|
|
22
|
+
}
|
|
23
|
+
initialized = true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class HostError extends Error {
|
|
27
|
+
code: string;
|
|
28
|
+
constructor(code: string, message: string) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.code = code;
|
|
31
|
+
this.name = "HostError";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function unwrap(result: { ok: boolean; data?: unknown; error?: { code: string; message: string } }): unknown {
|
|
36
|
+
if (!result.ok) {
|
|
37
|
+
throw new HostError(result.error!.code, result.error!.message);
|
|
38
|
+
}
|
|
39
|
+
return result.data;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Build a successful tool result payload. */
|
|
43
|
+
export function toolResult(text: string, opts: { terminate?: boolean; details?: object } = {}) {
|
|
44
|
+
const payload: {
|
|
45
|
+
content: Array<{ type: "text"; text: string }>;
|
|
46
|
+
terminate?: boolean;
|
|
47
|
+
details?: object;
|
|
48
|
+
} = {
|
|
49
|
+
content: [{ type: "text", text }],
|
|
50
|
+
};
|
|
51
|
+
if (opts.terminate) {
|
|
52
|
+
payload.terminate = true;
|
|
53
|
+
}
|
|
54
|
+
if (opts.details) {
|
|
55
|
+
payload.details = opts.details;
|
|
56
|
+
}
|
|
57
|
+
return payload;
|
|
58
|
+
}
|