@pi-oxide/pi-host-web 0.3.0 → 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 +36 -5
- package/pi_host_web.d.ts +98 -197
- package/pi_host_web.js +224 -97
- 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 -39
- package/sdk/index.js +86 -191
- 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/snapshot.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// SnapshotSerializer: converts between internal PersistData and public AgentSnapshot.
|
|
2
|
+
// Validates version and rejects unknown versions (returns null).
|
|
3
|
+
|
|
4
|
+
import type { AgentSnapshot } from "./types.ts";
|
|
5
|
+
|
|
6
|
+
const CURRENT_VERSION = 1;
|
|
7
|
+
|
|
8
|
+
export class SnapshotSerializer {
|
|
9
|
+
serialize(data: unknown): AgentSnapshot {
|
|
10
|
+
return {
|
|
11
|
+
version: CURRENT_VERSION,
|
|
12
|
+
data,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
deserialize(snapshot: AgentSnapshot): unknown | null {
|
|
17
|
+
if (snapshot.version !== CURRENT_VERSION) {
|
|
18
|
+
console.warn(
|
|
19
|
+
`Snapshot version mismatch: expected ${CURRENT_VERSION}, got ${snapshot.version}. Starting fresh.`,
|
|
20
|
+
);
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return snapshot.data;
|
|
24
|
+
}
|
|
25
|
+
}
|
package/sdk/stores.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Public store API for the pi-oxide SDK.
|
|
2
|
+
// Stores persist opaque snapshots; they do not interpret transcript internals.
|
|
3
|
+
|
|
4
|
+
import { indexedDbStore as internalIndexedDbStore } from "./internal/stores/indexedDb.ts";
|
|
5
|
+
import type { AgentStore, AgentSnapshot } from "./types.ts";
|
|
6
|
+
|
|
7
|
+
export { type AgentStore, type AgentSnapshot } from "./types.ts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Store backed by IndexedDB. Durable across page reloads.
|
|
11
|
+
*/
|
|
12
|
+
export function indexedDbStore(): AgentStore {
|
|
13
|
+
return internalIndexedDbStore();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* In-memory store. Session data is lost when the page reloads.
|
|
18
|
+
*/
|
|
19
|
+
export function memoryStore(): AgentStore {
|
|
20
|
+
const sessions = new Map<string, AgentSnapshot>();
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
async loadSession(sessionId: string): Promise<AgentSnapshot | null> {
|
|
24
|
+
return sessions.get(sessionId) ?? null;
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
async saveSession(sessionId: string, snapshot: AgentSnapshot): Promise<void> {
|
|
28
|
+
sessions.set(sessionId, snapshot);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Store backed by localStorage. Simple but limited by storage quotas.
|
|
35
|
+
*/
|
|
36
|
+
export function localStorageStore(): AgentStore {
|
|
37
|
+
return {
|
|
38
|
+
async loadSession(sessionId: string): Promise<AgentSnapshot | null> {
|
|
39
|
+
const raw = localStorage.getItem(`pi-oxide-session-${sessionId}`);
|
|
40
|
+
if (!raw) return null;
|
|
41
|
+
return JSON.parse(raw) as AgentSnapshot;
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
async saveSession(sessionId: string, snapshot: AgentSnapshot): Promise<void> {
|
|
45
|
+
localStorage.setItem(`pi-oxide-session-${sessionId}`, JSON.stringify(snapshot));
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Store backed by an HTTP API.
|
|
52
|
+
* Expects endpoints at `${baseUrl}/sessions/${sessionId}`.
|
|
53
|
+
*/
|
|
54
|
+
export function httpStore(config: { baseUrl: string }): AgentStore {
|
|
55
|
+
const baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
async loadSession(sessionId: string): Promise<AgentSnapshot | null> {
|
|
59
|
+
const resp = await fetch(`${baseUrl}/sessions/${sessionId}`);
|
|
60
|
+
if (!resp.ok) return null;
|
|
61
|
+
return resp.json() as Promise<AgentSnapshot>;
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
async saveSession(sessionId: string, snapshot: AgentSnapshot): Promise<void> {
|
|
65
|
+
await fetch(`${baseUrl}/sessions/${sessionId}`, {
|
|
66
|
+
method: "PUT",
|
|
67
|
+
headers: { "Content-Type": "application/json" },
|
|
68
|
+
body: JSON.stringify(snapshot),
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
package/sdk/tools.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Public tool API for the pi-oxide SDK.
|
|
2
|
+
// Tools are easy to declare and strongly typed at the boundary.
|
|
3
|
+
|
|
4
|
+
import type { ZodType } from "zod";
|
|
5
|
+
import type { AgentToolDefinition, AgentTools } from "./types.ts";
|
|
6
|
+
|
|
7
|
+
export interface ToolConfig<Input, Output> {
|
|
8
|
+
description: string;
|
|
9
|
+
input: ZodType<Input>;
|
|
10
|
+
run: (input: Input) => Promise<Output> | Output;
|
|
11
|
+
details?: (output: Output) => Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Declare a single tool definition with a Zod schema for input validation.
|
|
16
|
+
* The `name` is filled in by `defineTools()`.
|
|
17
|
+
*/
|
|
18
|
+
export function tool<Input, Output>(config: ToolConfig<Input, Output>): AgentToolDefinition {
|
|
19
|
+
return {
|
|
20
|
+
name: "",
|
|
21
|
+
description: config.description,
|
|
22
|
+
inputSchema: config.input,
|
|
23
|
+
run: config.run as (input: unknown) => Promise<unknown> | unknown,
|
|
24
|
+
details: config.details
|
|
25
|
+
? (config.details as (output: unknown) => Record<string, unknown>)
|
|
26
|
+
: undefined,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Build a mergeable AgentTools pack from a record of tool definitions.
|
|
32
|
+
* Multiple packs can be composed as an array in AgentConfig.tools.
|
|
33
|
+
*/
|
|
34
|
+
export function defineTools(tools: Record<string, AgentToolDefinition>): AgentTools {
|
|
35
|
+
const entries = Object.entries(tools).map(([name, def]) => ({
|
|
36
|
+
...def,
|
|
37
|
+
name,
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
definitions: entries,
|
|
42
|
+
getHandler(name: string) {
|
|
43
|
+
const def = entries.find((d) => d.name === name);
|
|
44
|
+
return def?.run ?? null;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
package/sdk/types.ts
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// Public type definitions for the pi-oxide SDK.
|
|
2
|
+
// No WASM imports in this file — these are pure TypeScript contracts.
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
AgentArtifact,
|
|
6
|
+
AgentArtifactRef,
|
|
7
|
+
ArtifactPolicy,
|
|
8
|
+
ArtifactSearchQuery,
|
|
9
|
+
ArtifactSearchResult,
|
|
10
|
+
} from "./artifacts.ts";
|
|
11
|
+
|
|
12
|
+
export type {
|
|
13
|
+
AgentArtifact,
|
|
14
|
+
AgentArtifactRef,
|
|
15
|
+
ArtifactPolicy,
|
|
16
|
+
ArtifactSearchQuery,
|
|
17
|
+
ArtifactSearchResult,
|
|
18
|
+
} from "./artifacts.ts";
|
|
19
|
+
|
|
20
|
+
export interface AgentConfig {
|
|
21
|
+
sessionId: string;
|
|
22
|
+
model: AgentModel;
|
|
23
|
+
tools?: AgentTools | AgentTools[];
|
|
24
|
+
store?: AgentStore;
|
|
25
|
+
instructions?: string;
|
|
26
|
+
context?: AgentContextPolicy;
|
|
27
|
+
artifacts?: ArtifactPolicy;
|
|
28
|
+
telemetry?: AgentTelemetry;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type AgentInput =
|
|
32
|
+
| string
|
|
33
|
+
| {
|
|
34
|
+
text: string;
|
|
35
|
+
attachments?: AgentAttachment[];
|
|
36
|
+
metadata?: Record<string, unknown>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export interface AgentAttachment {
|
|
40
|
+
type: string;
|
|
41
|
+
content: string | Uint8Array;
|
|
42
|
+
mimeType?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface AgentRunOptions {
|
|
46
|
+
signal?: AbortSignal;
|
|
47
|
+
metadata?: Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface AgentRunResult {
|
|
51
|
+
status: "completed" | "aborted" | "failed";
|
|
52
|
+
message?: AgentMessage;
|
|
53
|
+
text: string;
|
|
54
|
+
toolCalls: AgentToolRun[];
|
|
55
|
+
artifacts: AgentArtifactRef[];
|
|
56
|
+
usage?: TokenUsage;
|
|
57
|
+
error?: AgentError;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type AgentEventName =
|
|
61
|
+
| "messageStart"
|
|
62
|
+
| "text"
|
|
63
|
+
| "messageEnd"
|
|
64
|
+
| "toolStart"
|
|
65
|
+
| "toolUpdate"
|
|
66
|
+
| "toolEnd"
|
|
67
|
+
| "artifact"
|
|
68
|
+
| "status"
|
|
69
|
+
| "done"
|
|
70
|
+
| "error"
|
|
71
|
+
| "debug";
|
|
72
|
+
|
|
73
|
+
export type AgentEventHandler<E extends AgentEventName> =
|
|
74
|
+
E extends "messageStart" ? (message: AgentMessage) => void :
|
|
75
|
+
E extends "text" ? (delta: string) => void :
|
|
76
|
+
E extends "messageEnd" ? (message: AgentMessage) => void :
|
|
77
|
+
E extends "toolStart" ? (tool: AgentToolRun) => void :
|
|
78
|
+
E extends "toolUpdate" ? (tool: AgentToolRun) => void :
|
|
79
|
+
E extends "toolEnd" ? (tool: AgentToolRun) => void :
|
|
80
|
+
E extends "artifact" ? (artifact: AgentArtifactRef) => void :
|
|
81
|
+
E extends "status" ? (status: AgentStatus) => void :
|
|
82
|
+
E extends "done" ? (result: AgentRunResult) => void :
|
|
83
|
+
E extends "error" ? (error: AgentError) => void :
|
|
84
|
+
E extends "debug" ? (event: unknown) => void :
|
|
85
|
+
never;
|
|
86
|
+
|
|
87
|
+
export interface AgentMessage {
|
|
88
|
+
id: string;
|
|
89
|
+
role: "user" | "assistant" | "tool_result";
|
|
90
|
+
content: AgentContentBlock[];
|
|
91
|
+
timestamp?: number;
|
|
92
|
+
tool_call_id?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export type AgentContentBlock =
|
|
96
|
+
| { type: "text"; text: string }
|
|
97
|
+
| { type: "tool_call"; id: string; name: string; arguments: unknown }
|
|
98
|
+
| { type: "image"; mimeType: string; data: string }
|
|
99
|
+
| { type: "file"; mimeType: string; data: string };
|
|
100
|
+
|
|
101
|
+
export interface AgentToolRun {
|
|
102
|
+
id: string;
|
|
103
|
+
name: string;
|
|
104
|
+
title?: string;
|
|
105
|
+
input: unknown;
|
|
106
|
+
output?: unknown;
|
|
107
|
+
status: "running" | "completed" | "failed" | "cancelled";
|
|
108
|
+
startedAt: number;
|
|
109
|
+
endedAt?: number;
|
|
110
|
+
error?: AgentError;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface AgentStatus {
|
|
114
|
+
state:
|
|
115
|
+
| "idle"
|
|
116
|
+
| "loading"
|
|
117
|
+
| "thinking"
|
|
118
|
+
| "calling_model"
|
|
119
|
+
| "running_tool"
|
|
120
|
+
| "saving"
|
|
121
|
+
| "completed"
|
|
122
|
+
| "aborted"
|
|
123
|
+
| "failed";
|
|
124
|
+
message?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface AgentModel {
|
|
128
|
+
id?: string;
|
|
129
|
+
contextWindow?: number;
|
|
130
|
+
maxTokens?: number;
|
|
131
|
+
capabilities?: {
|
|
132
|
+
vision?: boolean;
|
|
133
|
+
jsonMode?: boolean;
|
|
134
|
+
functionCalling?: boolean;
|
|
135
|
+
streaming?: boolean;
|
|
136
|
+
};
|
|
137
|
+
generate(request: ModelRequest): Promise<ModelResponse>;
|
|
138
|
+
summarize?(messages: AgentMessage[], signal?: AbortSignal): Promise<string>;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface ModelRequest {
|
|
142
|
+
instructions: string;
|
|
143
|
+
messages: AgentMessage[];
|
|
144
|
+
tools: AgentToolDefinition[];
|
|
145
|
+
signal?: AbortSignal;
|
|
146
|
+
metadata?: Record<string, unknown>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface ModelResponse {
|
|
150
|
+
content: AgentContentBlock[];
|
|
151
|
+
stopReason: "end" | "tool_call" | "length" | "error";
|
|
152
|
+
usage?: TokenUsage;
|
|
153
|
+
model?: string;
|
|
154
|
+
raw?: unknown;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface ModelEvent {
|
|
158
|
+
type: "text_delta" | "tool_call_delta" | "done";
|
|
159
|
+
payload: unknown;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface AgentTools {
|
|
163
|
+
definitions: AgentToolDefinition[];
|
|
164
|
+
getHandler(name: string): ((input: unknown) => Promise<unknown> | unknown) | null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface AgentToolDefinition {
|
|
168
|
+
name: string;
|
|
169
|
+
description: string;
|
|
170
|
+
inputSchema: unknown; // ZodType, but we avoid importing zod in public types
|
|
171
|
+
run: (input: unknown) => Promise<unknown> | unknown;
|
|
172
|
+
details?: (output: unknown) => Record<string, unknown>;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface AgentStore {
|
|
176
|
+
loadSession(sessionId: string): Promise<AgentSnapshot | null>;
|
|
177
|
+
saveSession(sessionId: string, snapshot: AgentSnapshot): Promise<void>;
|
|
178
|
+
saveArtifact?(sessionId: string, artifact: AgentArtifact): Promise<void>;
|
|
179
|
+
loadArtifact?(sessionId: string, artifactId: string): Promise<AgentArtifact | null>;
|
|
180
|
+
searchArtifacts?(sessionId: string, query: ArtifactSearchQuery): Promise<ArtifactSearchResult[]>;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface AgentSnapshot {
|
|
184
|
+
version: number;
|
|
185
|
+
data: unknown;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export interface AgentContextPolicy {
|
|
189
|
+
maxTokens?: number;
|
|
190
|
+
toolResultLimit?: number;
|
|
191
|
+
strategy?:
|
|
192
|
+
| { type: "keep_full" }
|
|
193
|
+
| { type: "head"; tokens: number }
|
|
194
|
+
| { type: "tail"; tokens: number }
|
|
195
|
+
| { type: "head_tail"; headTokens: number; tailTokens: number }
|
|
196
|
+
| { type: "drop_if_old"; maxAgeMs: number };
|
|
197
|
+
summarize?: boolean | AgentSummarizer;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export interface AgentSummarizer {
|
|
201
|
+
summarize(messages: AgentMessage[]): Promise<string>;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface AgentTelemetry {
|
|
205
|
+
onEvent?(event: { type: string; payload: unknown }): void;
|
|
206
|
+
onMetric?(name: string, value: number, metadata?: Record<string, unknown>): void;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface AgentError {
|
|
210
|
+
code:
|
|
211
|
+
| "model_auth_failed"
|
|
212
|
+
| "model_rate_limited"
|
|
213
|
+
| "model_unavailable"
|
|
214
|
+
| "tool_input_invalid"
|
|
215
|
+
| "tool_failed"
|
|
216
|
+
| "tool_duplicate"
|
|
217
|
+
| "store_load_failed"
|
|
218
|
+
| "store_save_failed"
|
|
219
|
+
| "store_artifact_unsupported"
|
|
220
|
+
| "snapshot_invalid"
|
|
221
|
+
| "aborted"
|
|
222
|
+
| "internal_error"
|
|
223
|
+
| "agent_disposed"
|
|
224
|
+
| "agent_busy"
|
|
225
|
+
| "agent_not_initialized";
|
|
226
|
+
message: string;
|
|
227
|
+
cause?: unknown;
|
|
228
|
+
recoverable: boolean;
|
|
229
|
+
metadata?: Record<string, unknown>;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export interface TokenUsage {
|
|
233
|
+
input: number;
|
|
234
|
+
output: number;
|
|
235
|
+
cache_read: number;
|
|
236
|
+
cache_write: number;
|
|
237
|
+
total_tokens: number;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export interface UseAgentResult {
|
|
241
|
+
send(input: string | AgentInput, options?: AgentRunOptions): Promise<AgentRunResult>;
|
|
242
|
+
stop(reason?: string): void;
|
|
243
|
+
steer(input: string | AgentInput): Promise<void>;
|
|
244
|
+
reset(): Promise<void>;
|
|
245
|
+
status: AgentStatus;
|
|
246
|
+
messages: AgentMessage[];
|
|
247
|
+
toolCalls: AgentToolRun[];
|
|
248
|
+
artifacts: AgentArtifactRef[];
|
|
249
|
+
error: AgentError | null;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export type Unsubscribe = () => void;
|