@fungi.computer/parakeet 0.2.0 → 0.3.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/README.md CHANGED
@@ -70,6 +70,9 @@ does not cancel accepted work or close a borrowed Agent. When replacing a
70
70
  Session, provide its new handle rather than copying a snapshot into another
71
71
  writable store.
72
72
 
73
+ On touch-primary devices, Enter inserts a newline and the Send button submits
74
+ the draft. On desktop, Enter submits and Shift+Enter inserts a newline.
75
+
73
76
  The [standalone composer tests](test/standalone-composer.test.tsx) exercise the
74
77
  provider, query cache, observations and prompt admission with typed fixtures.
75
78
  The browser contract uses the real component with a fixture Session. A fake
@@ -140,7 +140,9 @@ function HostComposerTextarea({ placeholder, onChange, onSend, onAbort, slash, s
140
140
  });
141
141
  return;
142
142
  }
143
- if (event.key === "Enter" && !event.shiftKey) {
143
+ if (event.key === "Enter" &&
144
+ !event.shiftKey &&
145
+ !window.matchMedia("(pointer: coarse)").matches) {
144
146
  event.preventDefault();
145
147
  saveAndSend();
146
148
  return;
@@ -44,7 +44,7 @@ export const TimelineItem = memo(function TimelineItem({ item, onDismissFailed,
44
44
  case "assistant_message":
45
45
  if (!assistantMessageVisible(item))
46
46
  return null;
47
- return (_jsxs(_Fragment, { children: [item.author ? (_jsx("div", { className: "px-3 text-xs text-dim", "data-author": item.author.id, children: item.author.name })) : null, _jsx(ChatMessage, { isError: item.isError === true, pending: item.pending, speaker: "agent", ...(item.thinking ? { thinking: item.thinking } : {}), children: formatAssistantText?.(item.text) ?? item.text }), !item.pending && !item.isError
47
+ return (_jsxs(_Fragment, { children: [item.author ? (_jsx("div", { className: "px-3 text-xs text-dim", "data-author": item.author.id, children: item.author.name })) : null, _jsx(ChatMessage, { isError: item.isError === true, pending: item.pending, speaker: "agent", ...(item.thinking ? { thinking: item.thinking } : {}), children: formatAssistantText?.(item.text) ?? item.text }), item.isError && item.providerError !== undefined ? (_jsxs("div", { className: "px-3 text-error", "data-provider-error": item.id, children: [_jsx("p", { className: "whitespace-pre-wrap", children: item.providerError }), _jsxs("details", { children: [_jsx("summary", { children: "Provider details" }), _jsx("pre", { className: "whitespace-pre-wrap", children: item.providerError })] })] })) : null, !item.pending && !item.isError
48
48
  ? renderAssistantAttachment?.(item.text)
49
49
  : null] }));
50
50
  case "tool_group":
@@ -96,9 +96,12 @@ function assistantMessageItem(id, value, blocks) {
96
96
  tokens: value.usage.totalTokens,
97
97
  },
98
98
  };
99
+ const withProviderError = value.stopReason === "error" && value.providerError !== undefined
100
+ ? { ...item, providerError: value.providerError }
101
+ : item;
99
102
  return blocks.thinking.length === 0
100
- ? item
101
- : { ...item, thinking: blocks.thinking.join("\n") };
103
+ ? withProviderError
104
+ : { ...withProviderError, thinking: blocks.thinking.join("\n") };
102
105
  }
103
106
  function projectAssistant(id, value, author) {
104
107
  const blocks = collectAssistantBlocks(value);
@@ -116,6 +116,10 @@ export function applySessionFrame(current, frame) {
116
116
  compactions: mergeCompactions([], frame.baseline.compactions ?? []),
117
117
  compactionNotices: mergeCompactionNotices([], frame.baseline.compactionNotices ?? []),
118
118
  };
119
+ if (frame.kind === "activity")
120
+ return sameActivity(current.activity, frame.activity)
121
+ ? current
122
+ : { ...current, activity: frame.activity };
119
123
  if (frame.kind === "tool_output") {
120
124
  const completed = new Set(current.messages.flatMap((message) => message.value.role === "toolResult" ? [message.value.toolCallId] : []));
121
125
  const toolOutput = frame.toolOutput
@@ -71,6 +71,8 @@ export type AssistantMessageItem = Readonly<{
71
71
  at?: number;
72
72
  /** Assistant-visible response text. */
73
73
  text: string;
74
+ /** Pi's private failed-turn error text; never a terminal or delegation diagnostic. */
75
+ providerError?: string;
74
76
  /** Assistant reasoning text, when supplied by the model. */
75
77
  thinking?: string;
76
78
  /** Usage carried by the exact assistant message. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fungi.computer/parakeet",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "author": "Levi <levi@technomancy.dev>",
5
5
  "private": false,
6
6
  "description": "Standalone React composer for a typed Shiitake Session",
@@ -47,11 +47,11 @@
47
47
  "react-dom": "^18.2.0 || ^19.2.0"
48
48
  },
49
49
  "dependencies": {
50
- "@fungi.computer/agar": "0.3.0",
50
+ "@fungi.computer/agar": "0.3.1",
51
51
  "@fungi.computer/cairn": "0.1.0",
52
- "@fungi.computer/caps": "0.2.0",
53
- "@fungi.computer/knapsack": "0.2.0",
54
- "@fungi.computer/shiitake": "0.3.0",
52
+ "@fungi.computer/caps": "0.3.0",
53
+ "@fungi.computer/knapsack": "0.3.0",
54
+ "@fungi.computer/shiitake": "0.4.0",
55
55
  "@fungi.computer/sigils": "0.2.0",
56
56
  "@fungi.computer/sprite": "0.2.0",
57
57
  "@fungi.computer/sprite-zdog": "0.2.0",