@parlor/chat 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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -2
  3. package/dist/events.d.ts +4 -0
  4. package/dist/events.d.ts.map +1 -0
  5. package/dist/events.js +12 -0
  6. package/dist/events.js.map +1 -0
  7. package/dist/id-schemas.d.ts +5 -0
  8. package/dist/id-schemas.d.ts.map +1 -0
  9. package/dist/id-schemas.js +11 -0
  10. package/dist/id-schemas.js.map +1 -0
  11. package/dist/index.d.ts +9 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +7 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/items.d.ts +295 -0
  16. package/dist/items.d.ts.map +1 -0
  17. package/dist/items.js +113 -0
  18. package/dist/items.js.map +1 -0
  19. package/dist/limits.d.ts +4 -0
  20. package/dist/limits.d.ts.map +1 -0
  21. package/dist/limits.js +4 -0
  22. package/dist/limits.js.map +1 -0
  23. package/dist/model.d.ts +143 -0
  24. package/dist/model.d.ts.map +1 -0
  25. package/dist/model.js +2 -0
  26. package/dist/model.js.map +1 -0
  27. package/dist/open-turns.d.ts +19 -0
  28. package/dist/open-turns.d.ts.map +1 -0
  29. package/dist/open-turns.js +31 -0
  30. package/dist/open-turns.js.map +1 -0
  31. package/dist/protocol.d.ts +69 -0
  32. package/dist/protocol.d.ts.map +1 -0
  33. package/dist/protocol.js +80 -0
  34. package/dist/protocol.js.map +1 -0
  35. package/dist/server/actions.d.ts +561 -0
  36. package/dist/server/actions.d.ts.map +1 -0
  37. package/dist/server/actions.js +422 -0
  38. package/dist/server/actions.js.map +1 -0
  39. package/dist/server/context.d.ts +24 -0
  40. package/dist/server/context.d.ts.map +1 -0
  41. package/dist/server/context.js +77 -0
  42. package/dist/server/context.js.map +1 -0
  43. package/dist/server/index.d.ts +50 -0
  44. package/dist/server/index.d.ts.map +1 -0
  45. package/dist/server/index.js +145 -0
  46. package/dist/server/index.js.map +1 -0
  47. package/dist/server/live.d.ts +24 -0
  48. package/dist/server/live.d.ts.map +1 -0
  49. package/dist/server/live.js +130 -0
  50. package/dist/server/live.js.map +1 -0
  51. package/dist/server/migrations.d.ts +3 -0
  52. package/dist/server/migrations.d.ts.map +1 -0
  53. package/dist/server/migrations.js +96 -0
  54. package/dist/server/migrations.js.map +1 -0
  55. package/dist/server/party.d.ts +24 -0
  56. package/dist/server/party.d.ts.map +1 -0
  57. package/dist/server/party.js +38 -0
  58. package/dist/server/party.js.map +1 -0
  59. package/dist/server/routes.d.ts +17 -0
  60. package/dist/server/routes.d.ts.map +1 -0
  61. package/dist/server/routes.js +105 -0
  62. package/dist/server/routes.js.map +1 -0
  63. package/dist/server/rows.d.ts +49 -0
  64. package/dist/server/rows.d.ts.map +1 -0
  65. package/dist/server/rows.js +136 -0
  66. package/dist/server/rows.js.map +1 -0
  67. package/dist/server/store.d.ts +130 -0
  68. package/dist/server/store.d.ts.map +1 -0
  69. package/dist/server/store.js +539 -0
  70. package/dist/server/store.js.map +1 -0
  71. package/dist/tags.d.ts +7 -0
  72. package/dist/tags.d.ts.map +1 -0
  73. package/dist/tags.js +7 -0
  74. package/dist/tags.js.map +1 -0
  75. package/dist/testing/index.d.ts +46 -0
  76. package/dist/testing/index.d.ts.map +1 -0
  77. package/dist/testing/index.js +96 -0
  78. package/dist/testing/index.js.map +1 -0
  79. package/dist/view.d.ts +87 -0
  80. package/dist/view.d.ts.map +1 -0
  81. package/dist/view.js +236 -0
  82. package/dist/view.js.map +1 -0
  83. package/package.json +47 -3
package/dist/view.js ADDED
@@ -0,0 +1,236 @@
1
+ import { asId } from "@parlor/core";
2
+ const TERMINAL = new Set(["done", "failed", "cancelled"]);
3
+ /**
4
+ * Pure and O(items + open): the same input gives the same list with stable ids, so a
5
+ * durable item replacing its open twin keeps its React row.
6
+ */
7
+ export function foldThread(input) {
8
+ const states = new Map();
9
+ for (const turn of input.turns)
10
+ states.set(turn.turnId, turn.state);
11
+ const stateOf = (turnId) => states.get(turnId) ?? "done";
12
+ const failures = new Map();
13
+ for (const turn of input.turns) {
14
+ if (turn.failure)
15
+ failures.set(turn.turnId, turn.failure);
16
+ }
17
+ const rejected = new Set();
18
+ for (const item of input.items) {
19
+ if (item.kind === "event" &&
20
+ item.body.event === "answer_rejected" &&
21
+ item.body.itemId) {
22
+ rejected.add(item.body.itemId);
23
+ }
24
+ }
25
+ const rows = [];
26
+ const durable = new Set();
27
+ const asks = new Map();
28
+ const prompts = new Map();
29
+ const cancelled = new Set();
30
+ const push = (row) => {
31
+ rows.push(row);
32
+ return rows.length - 1;
33
+ };
34
+ const folders = {
35
+ prompt: (item) => {
36
+ prompts.set(item.turnId, push({
37
+ kind: "prompt",
38
+ id: item.id,
39
+ turnId: item.turnId,
40
+ text: item.body.text,
41
+ agent: item.body.agent,
42
+ state: stateOf(item.turnId),
43
+ failure: failures.get(item.turnId),
44
+ mine: input.deviceId !== undefined && item.body.signed?.deviceId === input.deviceId,
45
+ }));
46
+ },
47
+ answer: (item) => {
48
+ const at = asks.get(item.body.askId);
49
+ if (at === undefined || rejected.has(item.id))
50
+ return;
51
+ const row = rows[at];
52
+ if (row?.kind === "ask" && row.answer.state === "open") {
53
+ rows[at] = {
54
+ ...row,
55
+ answer: { state: "answered", choice: item.body.choice },
56
+ };
57
+ }
58
+ },
59
+ cancel: (item) => {
60
+ cancelled.add(item.turnId);
61
+ },
62
+ reply: (item) => {
63
+ push({
64
+ kind: "reply",
65
+ id: item.id,
66
+ turnId: item.turnId,
67
+ text: item.body.text,
68
+ streaming: false,
69
+ interrupted: item.body.interrupted === true,
70
+ });
71
+ },
72
+ reasoning: (item) => {
73
+ push({
74
+ kind: "reasoning",
75
+ id: item.id,
76
+ turnId: item.turnId,
77
+ text: item.body.text,
78
+ streaming: false,
79
+ interrupted: false,
80
+ });
81
+ },
82
+ tool: (item) => {
83
+ push({
84
+ kind: "tool",
85
+ id: item.id,
86
+ turnId: item.turnId,
87
+ title: item.body.title,
88
+ tool: item.body.tool,
89
+ status: item.body.status,
90
+ detail: item.body.detail,
91
+ });
92
+ },
93
+ plan: (item) => {
94
+ push({
95
+ kind: "plan",
96
+ id: item.id,
97
+ turnId: item.turnId,
98
+ entries: item.body.entries,
99
+ streaming: false,
100
+ });
101
+ },
102
+ ask: (item) => {
103
+ asks.set(item.id, push({
104
+ kind: "ask",
105
+ id: item.id,
106
+ turnId: item.turnId,
107
+ question: item.body.question,
108
+ choices: item.body.choices,
109
+ form: item.body.form,
110
+ approval: item.body.approval,
111
+ answer: { state: "open" },
112
+ }));
113
+ },
114
+ event: (item) => {
115
+ const { event, itemId, choice } = item.body;
116
+ if (event === "answered_on_computer") {
117
+ const at = itemId === undefined ? undefined : asks.get(itemId);
118
+ const row = at === undefined ? undefined : rows[at];
119
+ if (at !== undefined &&
120
+ choice !== undefined &&
121
+ row?.kind === "ask" &&
122
+ row.answer.state === "open") {
123
+ rows[at] = { ...row, answer: { state: "answered", choice } };
124
+ }
125
+ return;
126
+ }
127
+ push({
128
+ kind: "event",
129
+ id: item.id,
130
+ turnId: item.turnId,
131
+ event,
132
+ detail: item.body.detail,
133
+ });
134
+ },
135
+ };
136
+ for (const item of input.items) {
137
+ durable.add(item.id);
138
+ fold(folders, item);
139
+ }
140
+ for (const [turnId, at] of prompts) {
141
+ const row = rows[at];
142
+ if (row?.kind === "prompt" && cancelled.has(turnId) && !TERMINAL.has(row.state)) {
143
+ rows[at] = { ...row, state: "cancelled" };
144
+ }
145
+ }
146
+ for (const at of asks.values()) {
147
+ const row = rows[at];
148
+ if (row?.kind === "ask" && row.answer.state === "open") {
149
+ if (TERMINAL.has(stateOf(row.turnId)) || cancelled.has(row.turnId)) {
150
+ rows[at] = { ...row, answer: { state: "closed" } };
151
+ }
152
+ }
153
+ }
154
+ for (const turn of input.open) {
155
+ if (TERMINAL.has(stateOf(turn.turnId)))
156
+ continue;
157
+ for (const open of turn.items) {
158
+ if (durable.has(open.id))
159
+ continue;
160
+ rows.push(openRow(open, turn.turnId));
161
+ }
162
+ }
163
+ const threadId = input.items[0]?.threadId ?? input.open[0]?.threadId;
164
+ if (threadId !== undefined) {
165
+ const running = input.turns.find((turn) => turn.state === "running")?.turnId;
166
+ const turnId = running ?? input.items.at(-1)?.turnId ?? input.open[0]?.turnId;
167
+ if (turnId !== undefined) {
168
+ for (const confirmation of input.confirmations) {
169
+ if (confirmation.threadId !== threadId)
170
+ continue;
171
+ rows.push({
172
+ kind: "confirm",
173
+ id: asId("item", confirmation.id),
174
+ turnId,
175
+ confirmation,
176
+ });
177
+ }
178
+ }
179
+ }
180
+ return rows;
181
+ }
182
+ function fold(folders, item) {
183
+ switch (item.kind) {
184
+ case "prompt":
185
+ return folders.prompt(item);
186
+ case "answer":
187
+ return folders.answer(item);
188
+ case "cancel":
189
+ return folders.cancel(item);
190
+ case "reply":
191
+ return folders.reply(item);
192
+ case "reasoning":
193
+ return folders.reasoning(item);
194
+ case "tool":
195
+ return folders.tool(item);
196
+ case "plan":
197
+ return folders.plan(item);
198
+ case "ask":
199
+ return folders.ask(item);
200
+ case "event":
201
+ return folders.event(item);
202
+ }
203
+ }
204
+ function openRow(open, turnId) {
205
+ switch (open.kind) {
206
+ case "reply":
207
+ case "reasoning":
208
+ return {
209
+ kind: open.kind,
210
+ id: open.id,
211
+ turnId,
212
+ text: open.text,
213
+ streaming: true,
214
+ interrupted: false,
215
+ };
216
+ case "tool":
217
+ return {
218
+ kind: "tool",
219
+ id: open.id,
220
+ turnId,
221
+ title: open.title,
222
+ tool: undefined,
223
+ status: open.status,
224
+ detail: undefined,
225
+ };
226
+ case "plan":
227
+ return {
228
+ kind: "plan",
229
+ id: open.id,
230
+ turnId,
231
+ entries: open.entries,
232
+ streaming: true,
233
+ };
234
+ }
235
+ }
236
+ //# sourceMappingURL=view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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","sourcesContent":["import { asId, type DeviceId, type ItemId, type TurnId } from \"@parlor/core\";\n\nimport type { ChatEvent, FoldedEvent } from \"./events.js\";\nimport type { ChatItemBody, ChatItemKind, LoggedItem } from \"./items.js\";\nimport type {\n AgentRef,\n OpenItem,\n OpenTurn,\n TurnFailure,\n TurnState,\n TurnStatus,\n} from \"./model.js\";\n\nexport type AskState =\n | { readonly state: \"open\" }\n | { readonly state: \"answered\"; readonly choice: string }\n | { readonly state: \"closed\" };\n\n/** What a chat renders. `confirm` is the app's own `confirm: true` card, placed in its turn. */\nexport type ChatItem<C = unknown> =\n | {\n readonly kind: \"prompt\";\n readonly id: ItemId;\n readonly turnId: TurnId;\n readonly text: string;\n readonly agent: AgentRef;\n readonly state: TurnState;\n readonly failure: TurnFailure | undefined;\n readonly mine: boolean;\n }\n | {\n readonly kind: \"reply\" | \"reasoning\";\n readonly id: ItemId;\n readonly turnId: TurnId;\n readonly text: string;\n readonly streaming: boolean;\n readonly interrupted: boolean;\n }\n | {\n readonly kind: \"tool\";\n readonly id: ItemId;\n readonly turnId: TurnId;\n readonly title: string;\n readonly tool: ChatItemBody<\"tool\">[\"tool\"] | undefined;\n readonly status: \"pending\" | \"running\" | ChatItemBody<\"tool\">[\"status\"];\n readonly detail: string | undefined;\n }\n | {\n readonly kind: \"plan\";\n readonly id: ItemId;\n readonly turnId: TurnId;\n readonly entries: ChatItemBody<\"plan\">[\"entries\"];\n readonly streaming: boolean;\n }\n | {\n readonly kind: \"ask\";\n readonly id: ItemId;\n readonly turnId: TurnId;\n readonly question: string;\n readonly choices: ChatItemBody<\"ask\">[\"choices\"];\n readonly form: ChatItemBody<\"ask\">[\"form\"];\n readonly approval: ChatItemBody<\"ask\">[\"approval\"];\n readonly answer: AskState;\n }\n | {\n readonly kind: \"confirm\";\n readonly id: ItemId;\n readonly turnId: TurnId;\n readonly confirmation: C;\n }\n | {\n readonly kind: \"event\";\n readonly id: ItemId;\n readonly turnId: TurnId;\n readonly event: Exclude<ChatEvent, FoldedEvent>;\n readonly detail: string | undefined;\n };\n\n/** Log kinds that settle another item instead of rendering on their own. */\nexport type FoldedKind = Extract<ChatItemKind, \"answer\" | \"cancel\">;\n\nexport interface ThreadConfirmation {\n readonly id: string;\n readonly threadId?: string | undefined;\n}\n\nexport interface FoldInput<C extends ThreadConfirmation> {\n readonly items: readonly LoggedItem[];\n readonly open: readonly OpenTurn[];\n readonly turns: readonly TurnStatus[];\n readonly confirmations: readonly C[];\n readonly deviceId: DeviceId | undefined;\n}\n\n/** How each log kind enters the fold; keyed by every kind, so a new kind fails to build here. */\nexport type ItemFolders = {\n readonly [K in ChatItemKind]: (item: LoggedItem<K>) => void;\n};\n\nconst TERMINAL: ReadonlySet<TurnState> = new Set([\"done\", \"failed\", \"cancelled\"]);\n\n/**\n * Pure and O(items + open): the same input gives the same list with stable ids, so a\n * durable item replacing its open twin keeps its React row.\n */\nexport function foldThread<C extends ThreadConfirmation>(\n input: FoldInput<C>,\n): readonly ChatItem<C>[] {\n const states = new Map<TurnId, TurnState>();\n for (const turn of input.turns) states.set(turn.turnId, turn.state);\n const stateOf = (turnId: TurnId): TurnState => states.get(turnId) ?? \"done\";\n const failures = new Map<TurnId, TurnFailure>();\n for (const turn of input.turns) {\n if (turn.failure) failures.set(turn.turnId, turn.failure);\n }\n const rejected = new Set<ItemId>();\n for (const item of input.items) {\n if (\n item.kind === \"event\" &&\n item.body.event === \"answer_rejected\" &&\n item.body.itemId\n ) {\n rejected.add(item.body.itemId);\n }\n }\n\n const rows: ChatItem<C>[] = [];\n const durable = new Set<ItemId>();\n const asks = new Map<ItemId, number>();\n const prompts = new Map<TurnId, number>();\n const cancelled = new Set<TurnId>();\n\n const push = (row: ChatItem<C>) => {\n rows.push(row);\n return rows.length - 1;\n };\n\n const folders: ItemFolders = {\n prompt: (item) => {\n prompts.set(\n item.turnId,\n push({\n kind: \"prompt\",\n id: item.id,\n turnId: item.turnId,\n text: item.body.text,\n agent: item.body.agent,\n state: stateOf(item.turnId),\n failure: failures.get(item.turnId),\n mine:\n input.deviceId !== undefined && item.body.signed?.deviceId === input.deviceId,\n }),\n );\n },\n answer: (item) => {\n const at = asks.get(item.body.askId);\n if (at === undefined || rejected.has(item.id)) return;\n const row = rows[at];\n if (row?.kind === \"ask\" && row.answer.state === \"open\") {\n rows[at] = {\n ...row,\n answer: { state: \"answered\", choice: item.body.choice },\n };\n }\n },\n cancel: (item) => {\n cancelled.add(item.turnId);\n },\n reply: (item) => {\n push({\n kind: \"reply\",\n id: item.id,\n turnId: item.turnId,\n text: item.body.text,\n streaming: false,\n interrupted: item.body.interrupted === true,\n });\n },\n reasoning: (item) => {\n push({\n kind: \"reasoning\",\n id: item.id,\n turnId: item.turnId,\n text: item.body.text,\n streaming: false,\n interrupted: false,\n });\n },\n tool: (item) => {\n push({\n kind: \"tool\",\n id: item.id,\n turnId: item.turnId,\n title: item.body.title,\n tool: item.body.tool,\n status: item.body.status,\n detail: item.body.detail,\n });\n },\n plan: (item) => {\n push({\n kind: \"plan\",\n id: item.id,\n turnId: item.turnId,\n entries: item.body.entries,\n streaming: false,\n });\n },\n ask: (item) => {\n asks.set(\n item.id,\n push({\n kind: \"ask\",\n id: item.id,\n turnId: item.turnId,\n question: item.body.question,\n choices: item.body.choices,\n form: item.body.form,\n approval: item.body.approval,\n answer: { state: \"open\" },\n }),\n );\n },\n event: (item) => {\n const { event, itemId, choice } = item.body;\n if (event === \"answered_on_computer\") {\n const at = itemId === undefined ? undefined : asks.get(itemId);\n const row = at === undefined ? undefined : rows[at];\n if (\n at !== undefined &&\n choice !== undefined &&\n row?.kind === \"ask\" &&\n row.answer.state === \"open\"\n ) {\n rows[at] = { ...row, answer: { state: \"answered\", choice } };\n }\n return;\n }\n push({\n kind: \"event\",\n id: item.id,\n turnId: item.turnId,\n event,\n detail: item.body.detail,\n });\n },\n };\n\n for (const item of input.items) {\n durable.add(item.id);\n fold(folders, item);\n }\n\n for (const [turnId, at] of prompts) {\n const row = rows[at];\n if (row?.kind === \"prompt\" && cancelled.has(turnId) && !TERMINAL.has(row.state)) {\n rows[at] = { ...row, state: \"cancelled\" };\n }\n }\n for (const at of asks.values()) {\n const row = rows[at];\n if (row?.kind === \"ask\" && row.answer.state === \"open\") {\n if (TERMINAL.has(stateOf(row.turnId)) || cancelled.has(row.turnId)) {\n rows[at] = { ...row, answer: { state: \"closed\" } };\n }\n }\n }\n\n for (const turn of input.open) {\n if (TERMINAL.has(stateOf(turn.turnId))) continue;\n for (const open of turn.items) {\n if (durable.has(open.id)) continue;\n rows.push(openRow(open, turn.turnId));\n }\n }\n\n const threadId = input.items[0]?.threadId ?? input.open[0]?.threadId;\n if (threadId !== undefined) {\n const running = input.turns.find((turn) => turn.state === \"running\")?.turnId;\n const turnId = running ?? input.items.at(-1)?.turnId ?? input.open[0]?.turnId;\n if (turnId !== undefined) {\n for (const confirmation of input.confirmations) {\n if (confirmation.threadId !== threadId) continue;\n rows.push({\n kind: \"confirm\",\n id: asId(\"item\", confirmation.id),\n turnId,\n confirmation,\n });\n }\n }\n }\n return rows;\n}\n\nfunction fold(folders: ItemFolders, item: LoggedItem): void {\n switch (item.kind) {\n case \"prompt\":\n return folders.prompt(item);\n case \"answer\":\n return folders.answer(item);\n case \"cancel\":\n return folders.cancel(item);\n case \"reply\":\n return folders.reply(item);\n case \"reasoning\":\n return folders.reasoning(item);\n case \"tool\":\n return folders.tool(item);\n case \"plan\":\n return folders.plan(item);\n case \"ask\":\n return folders.ask(item);\n case \"event\":\n return folders.event(item);\n }\n}\n\nfunction openRow<C>(open: OpenItem, turnId: TurnId): ChatItem<C> {\n switch (open.kind) {\n case \"reply\":\n case \"reasoning\":\n return {\n kind: open.kind,\n id: open.id,\n turnId,\n text: open.text,\n streaming: true,\n interrupted: false,\n };\n case \"tool\":\n return {\n kind: \"tool\",\n id: open.id,\n turnId,\n title: open.title,\n tool: undefined,\n status: open.status,\n detail: undefined,\n };\n case \"plan\":\n return {\n kind: \"plan\",\n id: open.id,\n turnId,\n entries: open.entries,\n streaming: true,\n };\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,50 @@
1
1
  {
2
2
  "name": "@parlor/chat",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "homepage": "https://cychien.github.io/parlor",
5
+ "bugs": "https://github.com/cychien/parlor/issues",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/cychien/parlor.git",
10
+ "directory": "packages/chat"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "type": "module",
16
+ "sideEffects": false,
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js"
21
+ },
22
+ "./server": {
23
+ "types": "./dist/server/index.d.ts",
24
+ "import": "./dist/server/index.js"
25
+ },
26
+ "./testing": {
27
+ "types": "./dist/testing/index.d.ts",
28
+ "import": "./dist/testing/index.js"
29
+ }
30
+ },
31
+ "dependencies": {
32
+ "drizzle-orm": "^0.45.4",
33
+ "zod": "^4.6.5",
34
+ "@parlor/agent-ui": "0.2.0",
35
+ "@parlor/core": "0.2.0",
36
+ "@parlor/server": "0.2.0",
37
+ "@parlor/sync": "0.2.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^24.14.0",
41
+ "typescript": "^7.0.2",
42
+ "vitest": "^5.0.3",
43
+ "@parlor/data": "0.2.0"
44
+ },
45
+ "scripts": {
46
+ "build": "tsc -p tsconfig.json",
47
+ "typecheck": "tsc -p tsconfig.json --noEmit",
48
+ "test": "vitest run"
49
+ }
6
50
  }