echospace 0.1.0-alpha.1 → 0.1.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -58
- package/dist/cli/index.js +196 -48
- package/dist/client/assets/Geist-Italic-Variable-vKc54d3Z.woff2 +0 -0
- package/dist/client/assets/Geist-Variable-CrgPqtmy.woff2 +0 -0
- package/dist/client/assets/GeistMono-Italic-Variable-MBthCoE1.woff2 +0 -0
- package/dist/client/assets/GeistMono-Variable-BNLlm6Cd.woff2 +0 -0
- package/dist/client/assets/GeistPixel-Square-CwnHaJd_.woff2 +0 -0
- package/dist/client/assets/index-gZkfzHQ0.css +1 -0
- package/dist/client/assets/index-ja1djPyy.js +168 -0
- package/dist/client/echospace-logo.svg +12 -11
- package/dist/client/index.html +4 -10
- package/dist/core/chunk-LGVA3Y5G.js +110 -0
- package/dist/core/echo/index.d.ts +2 -2
- package/dist/core/echo/index.js +1 -1
- package/dist/core/providers/index.d.ts +1 -1
- package/dist/core/providers/index.js +3 -3
- package/dist/core/smart-paste/index.d.ts +1 -1
- package/dist/core/smart-paste/index.js +1 -1
- package/dist/core/types-DonjLc45.d.ts +89 -0
- package/package.json +3 -1
- package/dist/client/assets/index-C3HpfhnB.js +0 -168
- package/dist/client/assets/index-kxAuiugv.css +0 -1
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="131 131 250 250" width="512" height="512">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
<defs>
|
|
3
|
+
<mask id="cutout">
|
|
4
|
+
<rect x="131" y="131" width="250" height="250" fill="white"/>
|
|
5
|
+
<!-- Inner cutout -->
|
|
6
|
+
<rect x="168" y="168" width="176" height="176" rx="25" ry="25" fill="black"/>
|
|
7
|
+
<!-- Middle fill-back -->
|
|
8
|
+
<rect x="198" y="198" width="116" height="116" rx="18.3" ry="18.3" fill="white"/>
|
|
9
|
+
<!-- Center cutout -->
|
|
10
|
+
<rect x="226.3" y="226.3" width="59.3" height="59.3" rx="9.3" ry="9.3" fill="black"/>
|
|
11
|
+
</mask>
|
|
12
|
+
</defs>
|
|
13
|
+
<rect x="139.3" y="139.3" width="233.3" height="233.3" rx="36.7" ry="36.7" fill="currentColor" mask="url(#cutout)"/>
|
|
13
14
|
</svg>
|
package/dist/client/index.html
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
2
|
+
<html lang="en" style="overscroll-behavior: none">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>EchoSpace</title>
|
|
7
7
|
<link rel="icon" type="image/svg+xml" href="/echospace-logo.svg">
|
|
8
|
-
<
|
|
9
|
-
<link rel="
|
|
10
|
-
<link
|
|
11
|
-
href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,400&family=IBM+Plex+Mono:wght@400;500&display=swap"
|
|
12
|
-
rel="stylesheet"
|
|
13
|
-
/>
|
|
14
|
-
<script type="module" crossorigin src="/assets/index-C3HpfhnB.js"></script>
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/assets/index-kxAuiugv.css">
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-ja1djPyy.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-gZkfzHQ0.css">
|
|
16
10
|
</head>
|
|
17
|
-
<body>
|
|
11
|
+
<body style="width: 100%; height: 100%; margin: 0; overflow: hidden">
|
|
18
12
|
<div id="root"></div>
|
|
19
13
|
</body>
|
|
20
14
|
</html>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// src/core/echo/parser.ts
|
|
2
|
+
import { nanoid } from "nanoid";
|
|
3
|
+
function parseEcho(raw) {
|
|
4
|
+
const lines = raw.split("\n").filter((line) => line.trim().length > 0);
|
|
5
|
+
if (lines.length === 0) {
|
|
6
|
+
throw new Error("Empty .echo file");
|
|
7
|
+
}
|
|
8
|
+
const records = lines.map((line, i) => {
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(line);
|
|
11
|
+
} catch {
|
|
12
|
+
throw new Error(`Invalid JSON on line ${i + 1}`);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
const metaRecord = records[0];
|
|
16
|
+
if (!metaRecord || metaRecord.kind !== "meta") {
|
|
17
|
+
throw new Error("First line must be a meta record");
|
|
18
|
+
}
|
|
19
|
+
const messages = records.filter((r) => r.kind === "message").map(normalizeMessage);
|
|
20
|
+
return {
|
|
21
|
+
meta: metaRecord,
|
|
22
|
+
messages
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function normalizeMessage(message) {
|
|
26
|
+
const raw = message;
|
|
27
|
+
let msg = message;
|
|
28
|
+
if (!msg.id) {
|
|
29
|
+
msg = { ...msg, id: nanoid(8) };
|
|
30
|
+
}
|
|
31
|
+
if (!msg.created_at && (raw.ts || raw.timestamp)) {
|
|
32
|
+
msg = { ...msg, created_at: raw.ts ?? raw.timestamp };
|
|
33
|
+
}
|
|
34
|
+
const needsPartNormalization = msg.parts.some((p) => {
|
|
35
|
+
if (p.type !== "tool_result") return false;
|
|
36
|
+
const r = p;
|
|
37
|
+
return !r.tool_call_id && (r.id || r.tool_use_id);
|
|
38
|
+
});
|
|
39
|
+
if (needsPartNormalization) {
|
|
40
|
+
msg = {
|
|
41
|
+
...msg,
|
|
42
|
+
parts: msg.parts.map((p) => {
|
|
43
|
+
if (p.type !== "tool_result") return p;
|
|
44
|
+
const r = p;
|
|
45
|
+
if (!r.tool_call_id && (r.id || r.tool_use_id)) {
|
|
46
|
+
const { id, tool_use_id, ...rest } = r;
|
|
47
|
+
return { ...rest, tool_call_id: id ?? tool_use_id };
|
|
48
|
+
}
|
|
49
|
+
return p;
|
|
50
|
+
})
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return msg;
|
|
54
|
+
}
|
|
55
|
+
function serializeEcho(conversation) {
|
|
56
|
+
const records = [conversation.meta, ...conversation.messages];
|
|
57
|
+
return records.map((r) => JSON.stringify(r)).join("\n") + "\n";
|
|
58
|
+
}
|
|
59
|
+
function createConversation(id, title) {
|
|
60
|
+
return {
|
|
61
|
+
meta: {
|
|
62
|
+
kind: "meta",
|
|
63
|
+
v: 1,
|
|
64
|
+
id,
|
|
65
|
+
title,
|
|
66
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
67
|
+
},
|
|
68
|
+
messages: []
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function getMessageText(message) {
|
|
72
|
+
return message.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
73
|
+
}
|
|
74
|
+
function withUpdatedMeta(conversation, updates) {
|
|
75
|
+
return {
|
|
76
|
+
...conversation,
|
|
77
|
+
meta: { ...conversation.meta, ...updates }
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function withAppendedMessages(conversation, messages) {
|
|
81
|
+
return {
|
|
82
|
+
...conversation,
|
|
83
|
+
messages: [...conversation.messages, ...messages]
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function withUpdatedMessage(conversation, messageId, updates) {
|
|
87
|
+
return {
|
|
88
|
+
...conversation,
|
|
89
|
+
messages: conversation.messages.map(
|
|
90
|
+
(m) => m.id === messageId ? { ...m, ...updates } : m
|
|
91
|
+
)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function withRemovedMessage(conversation, messageId) {
|
|
95
|
+
return {
|
|
96
|
+
...conversation,
|
|
97
|
+
messages: conversation.messages.filter((m) => m.id !== messageId)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export {
|
|
102
|
+
parseEcho,
|
|
103
|
+
serializeEcho,
|
|
104
|
+
createConversation,
|
|
105
|
+
getMessageText,
|
|
106
|
+
withUpdatedMeta,
|
|
107
|
+
withAppendedMessages,
|
|
108
|
+
withUpdatedMessage,
|
|
109
|
+
withRemovedMessage
|
|
110
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as EchoConversation, a as EchoMessage, b as EchoMeta } from '../types-
|
|
2
|
-
export { c as EchoPart, d as EchoRecord, e as EchoRole, f as EchoSettings, g as EchoToolDefinition, I as ImagePart, T as TextPart, h as ThinkingPart, i as ToolCallPart, j as ToolResultPart } from '../types-
|
|
1
|
+
import { E as EchoConversation, a as EchoMessage, b as EchoMeta } from '../types-DonjLc45.js';
|
|
2
|
+
export { c as EchoPart, d as EchoRecord, e as EchoRole, f as EchoSettings, g as EchoToolDefinition, I as ImagePart, T as TextPart, h as ThinkingPart, i as ToolCallPart, j as ToolResultPart } from '../types-DonjLc45.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Parse an .echo NDJSON string into an EchoConversation.
|
package/dist/core/echo/index.js
CHANGED
|
@@ -20,7 +20,7 @@ function toAnthropicContent(msg) {
|
|
|
20
20
|
case "tool_result":
|
|
21
21
|
blocks.push({
|
|
22
22
|
type: "tool_result",
|
|
23
|
-
tool_use_id: part.
|
|
23
|
+
tool_use_id: part.tool_call_id,
|
|
24
24
|
content: typeof part.output === "string" ? part.output : JSON.stringify(part.output),
|
|
25
25
|
is_error: part.is_error
|
|
26
26
|
});
|
|
@@ -148,7 +148,7 @@ function toGeminiContent(msg) {
|
|
|
148
148
|
case "tool_result":
|
|
149
149
|
parts.push({
|
|
150
150
|
functionResponse: {
|
|
151
|
-
name: part.
|
|
151
|
+
name: part.tool_call_id,
|
|
152
152
|
response: { result: part.output }
|
|
153
153
|
}
|
|
154
154
|
});
|
|
@@ -255,7 +255,7 @@ function toOpenAIMessage(msg) {
|
|
|
255
255
|
if (msg.role === "tool" && toolResults.length > 0) {
|
|
256
256
|
const tr = toolResults[0];
|
|
257
257
|
result.content = typeof tr.output === "string" ? tr.output : JSON.stringify(tr.output);
|
|
258
|
-
result.tool_call_id = tr.
|
|
258
|
+
result.tool_call_id = tr.tool_call_id;
|
|
259
259
|
return result;
|
|
260
260
|
}
|
|
261
261
|
if (msg.role === "assistant") {
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Echo format types — the universal .echo message protocol.
|
|
3
|
+
*
|
|
4
|
+
* An .echo file is NDJSON (newline-delimited JSON).
|
|
5
|
+
* Line 1 is always an EchoMeta record.
|
|
6
|
+
* Subsequent lines are EchoMessage records.
|
|
7
|
+
*/
|
|
8
|
+
interface TextPart {
|
|
9
|
+
type: "text";
|
|
10
|
+
text: string;
|
|
11
|
+
}
|
|
12
|
+
interface ThinkingPart {
|
|
13
|
+
type: "thinking";
|
|
14
|
+
text: string;
|
|
15
|
+
}
|
|
16
|
+
interface ToolCallPart {
|
|
17
|
+
type: "tool_call";
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
input: unknown;
|
|
21
|
+
}
|
|
22
|
+
interface ToolResultPart {
|
|
23
|
+
type: "tool_result";
|
|
24
|
+
tool_call_id: string;
|
|
25
|
+
output: unknown;
|
|
26
|
+
is_error?: boolean;
|
|
27
|
+
}
|
|
28
|
+
interface ImagePart {
|
|
29
|
+
type: "image";
|
|
30
|
+
url?: string;
|
|
31
|
+
base64?: string;
|
|
32
|
+
media_type?: string;
|
|
33
|
+
}
|
|
34
|
+
type EchoPart = TextPart | ThinkingPart | ToolCallPart | ToolResultPart | ImagePart;
|
|
35
|
+
interface EchoToolDefinition {
|
|
36
|
+
name: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
parameters: Record<string, unknown>;
|
|
39
|
+
strict?: boolean;
|
|
40
|
+
}
|
|
41
|
+
interface EchoSettings {
|
|
42
|
+
provider?: string;
|
|
43
|
+
model?: string;
|
|
44
|
+
temperature?: number;
|
|
45
|
+
max_tokens?: number;
|
|
46
|
+
top_p?: number;
|
|
47
|
+
response_format?: "text" | "json_object" | "json_schema";
|
|
48
|
+
json_schema?: {
|
|
49
|
+
name: string;
|
|
50
|
+
schema: Record<string, unknown>;
|
|
51
|
+
strict?: boolean;
|
|
52
|
+
};
|
|
53
|
+
tools?: EchoToolDefinition[];
|
|
54
|
+
}
|
|
55
|
+
type EchoRole = "system" | "user" | "assistant" | "tool";
|
|
56
|
+
interface EchoMeta {
|
|
57
|
+
kind: "meta";
|
|
58
|
+
v: 1;
|
|
59
|
+
id: string;
|
|
60
|
+
title?: string;
|
|
61
|
+
created_at: string;
|
|
62
|
+
settings?: EchoSettings;
|
|
63
|
+
}
|
|
64
|
+
interface EchoMessage {
|
|
65
|
+
kind: "message";
|
|
66
|
+
id: string;
|
|
67
|
+
role: EchoRole;
|
|
68
|
+
created_at: string;
|
|
69
|
+
parts: EchoPart[];
|
|
70
|
+
meta?: {
|
|
71
|
+
provider?: string;
|
|
72
|
+
model?: string;
|
|
73
|
+
usage?: {
|
|
74
|
+
input_tokens?: number;
|
|
75
|
+
output_tokens?: number;
|
|
76
|
+
};
|
|
77
|
+
latency?: {
|
|
78
|
+
duration?: number;
|
|
79
|
+
ttft?: number;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
type EchoRecord = EchoMeta | EchoMessage;
|
|
84
|
+
interface EchoConversation {
|
|
85
|
+
meta: EchoMeta;
|
|
86
|
+
messages: EchoMessage[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type { EchoConversation as E, ImagePart as I, TextPart as T, EchoMessage as a, EchoMeta as b, EchoPart as c, EchoRecord as d, EchoRole as e, EchoSettings as f, EchoToolDefinition as g, ThinkingPart as h, ToolCallPart as i, ToolResultPart as j };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "echospace",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Open-source, local-first prompt debugging workspace for LLM developers",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,8 +56,10 @@
|
|
|
56
56
|
"format": "prettier --write ."
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
+
"@clack/prompts": "^1.1.0",
|
|
59
60
|
"@hono/node-server": "^1.13.8",
|
|
60
61
|
"commander": "^13.1.0",
|
|
62
|
+
"geist": "^1.7.0",
|
|
61
63
|
"get-port": "^7.1.0",
|
|
62
64
|
"hono": "^4.7.4",
|
|
63
65
|
"js-yaml": "^4.1.0",
|