@meetopenbot/pi 0.0.1 → 0.0.2
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/dist/format.js +45 -17
- package/dist/index.js +67 -3
- package/dist/stream.js +3 -3
- package/package.json +2 -2
package/dist/format.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const isAssistantMessage = (message) => message.role === 'assistant';
|
|
2
2
|
export const createStreamState = () => ({
|
|
3
3
|
assistantText: '',
|
|
4
|
-
lastYieldedText: '',
|
|
5
4
|
});
|
|
6
5
|
const strArg = (args, ...keys) => {
|
|
7
6
|
if (!args || typeof args !== 'object')
|
|
@@ -76,36 +75,47 @@ export const formatPiEvent = (event, state) => {
|
|
|
76
75
|
if (assistantEvent.type !== 'text_delta')
|
|
77
76
|
return undefined;
|
|
78
77
|
state.assistantText += assistantEvent.delta;
|
|
79
|
-
|
|
80
|
-
return undefined;
|
|
81
|
-
state.lastYieldedText = state.assistantText;
|
|
82
|
-
return state.assistantText;
|
|
78
|
+
return undefined;
|
|
83
79
|
}
|
|
84
80
|
case 'tool_execution_start': {
|
|
85
|
-
|
|
86
|
-
return
|
|
81
|
+
const statusLine = formatToolStart(event.toolName, event.args);
|
|
82
|
+
return {
|
|
83
|
+
type: 'tool_start',
|
|
84
|
+
toolCallId: event.toolCallId,
|
|
85
|
+
toolName: event.toolName,
|
|
86
|
+
args: event.args,
|
|
87
|
+
statusLine,
|
|
88
|
+
};
|
|
87
89
|
}
|
|
88
90
|
case 'tool_execution_end': {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
let statusLine;
|
|
92
|
+
if (event.isError) {
|
|
93
|
+
statusLine = `Tool **${event.toolName}** failed.`;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
type: 'tool_end',
|
|
97
|
+
toolCallId: event.toolCallId,
|
|
98
|
+
toolName: event.toolName,
|
|
99
|
+
result: event.result,
|
|
100
|
+
isError: event.isError,
|
|
101
|
+
statusLine,
|
|
102
|
+
};
|
|
93
103
|
}
|
|
94
104
|
case 'auto_retry_start': {
|
|
95
|
-
|
|
96
|
-
return
|
|
105
|
+
const statusLine = `Retrying (${event.attempt}/${event.maxAttempts})…`;
|
|
106
|
+
return { type: 'status', statusLine };
|
|
97
107
|
}
|
|
98
108
|
case 'compaction_start': {
|
|
99
|
-
|
|
100
|
-
return
|
|
109
|
+
const statusLine = 'Compacting conversation context…';
|
|
110
|
+
return { type: 'status', statusLine };
|
|
101
111
|
}
|
|
102
112
|
case 'agent_end': {
|
|
103
113
|
const lastAssistant = [...event.messages].reverse().find(isAssistantMessage);
|
|
104
114
|
if (lastAssistant?.stopReason === 'error' && lastAssistant.errorMessage?.trim()) {
|
|
105
|
-
return `**Pi error:** ${lastAssistant.errorMessage.trim()}
|
|
115
|
+
return { type: 'text', content: `**Pi error:** ${lastAssistant.errorMessage.trim()}` };
|
|
106
116
|
}
|
|
107
117
|
if (state.assistantText.trim()) {
|
|
108
|
-
return state.assistantText;
|
|
118
|
+
return { type: 'text', content: state.assistantText };
|
|
109
119
|
}
|
|
110
120
|
return undefined;
|
|
111
121
|
}
|
|
@@ -118,3 +128,21 @@ export const formatPiError = (error) => {
|
|
|
118
128
|
return error.message;
|
|
119
129
|
return String(error);
|
|
120
130
|
};
|
|
131
|
+
export const formatToolResult = (result) => {
|
|
132
|
+
if (!result)
|
|
133
|
+
return '';
|
|
134
|
+
if (typeof result === 'string')
|
|
135
|
+
return result;
|
|
136
|
+
if (result && typeof result === 'object' && Array.isArray(result.content)) {
|
|
137
|
+
return result.content
|
|
138
|
+
.map((c) => {
|
|
139
|
+
if (c.type === 'text')
|
|
140
|
+
return c.text;
|
|
141
|
+
if (c.type === 'image')
|
|
142
|
+
return `[Image: ${c.source?.data?.slice(0, 20)}...]`;
|
|
143
|
+
return `[${c.type}]`;
|
|
144
|
+
})
|
|
145
|
+
.join('\n');
|
|
146
|
+
}
|
|
147
|
+
return JSON.stringify(result, null, 2);
|
|
148
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { agentOutput, definePlugin, shouldHandleInvoke, } from '@meetopenbot/plugin-sdk';
|
|
1
|
+
import { agentOutput, definePlugin, shouldHandleInvoke, uiWidget, } from '@meetopenbot/plugin-sdk';
|
|
2
2
|
import { resolveConfig } from './config.js';
|
|
3
|
-
import { formatPiError } from './format.js';
|
|
3
|
+
import { formatPiError, formatToolResult } from './format.js';
|
|
4
4
|
import { getOrCreatePiSession } from './session.js';
|
|
5
5
|
import { streamPiPrompt } from './stream.js';
|
|
6
6
|
export default definePlugin({
|
|
@@ -73,12 +73,76 @@ export default definePlugin({
|
|
|
73
73
|
state: handlerCtx.state,
|
|
74
74
|
storage: context.storage,
|
|
75
75
|
});
|
|
76
|
+
let fullTextContent = '';
|
|
77
|
+
const toolInfoMap = new Map();
|
|
76
78
|
for await (const chunk of streamPiPrompt(session, prompt, {
|
|
77
79
|
streaming: session.isStreaming,
|
|
78
80
|
})) {
|
|
81
|
+
switch (chunk.type) {
|
|
82
|
+
case 'tool_start':
|
|
83
|
+
toolInfoMap.set(chunk.toolCallId, {
|
|
84
|
+
statusLine: chunk.statusLine,
|
|
85
|
+
args: chunk.args,
|
|
86
|
+
});
|
|
87
|
+
yield uiWidget({
|
|
88
|
+
agentId: context.agentId,
|
|
89
|
+
threadId,
|
|
90
|
+
widget: {
|
|
91
|
+
kind: 'message',
|
|
92
|
+
widgetId: chunk.toolCallId,
|
|
93
|
+
title: chunk.statusLine,
|
|
94
|
+
body: `**Input**\n\`\`\`json\n${JSON.stringify(chunk.args, null, 2)}\n\`\`\``,
|
|
95
|
+
variant: 'basic',
|
|
96
|
+
display: "collapsed",
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
break;
|
|
100
|
+
case 'tool_end': {
|
|
101
|
+
const info = toolInfoMap.get(chunk.toolCallId);
|
|
102
|
+
const inputMd = info
|
|
103
|
+
? `**Input**\n\`\`\`json\n${JSON.stringify(info.args, null, 2)}\n\`\`\`\n\n`
|
|
104
|
+
: '';
|
|
105
|
+
const outputMd = `**Output**\n${formatToolResult(chunk.result)}`;
|
|
106
|
+
yield uiWidget({
|
|
107
|
+
agentId: context.agentId,
|
|
108
|
+
threadId,
|
|
109
|
+
widget: {
|
|
110
|
+
kind: 'message',
|
|
111
|
+
widgetId: chunk.toolCallId,
|
|
112
|
+
title: chunk.statusLine || info?.statusLine || `Tool ${chunk.toolName} finished`,
|
|
113
|
+
body: inputMd + outputMd,
|
|
114
|
+
variant: 'basic',
|
|
115
|
+
display: "collapsed",
|
|
116
|
+
state: chunk.isError ? 'error' : 'submitted',
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
case 'status':
|
|
122
|
+
yield uiWidget({
|
|
123
|
+
agentId: context.agentId,
|
|
124
|
+
threadId,
|
|
125
|
+
widget: {
|
|
126
|
+
kind: 'message',
|
|
127
|
+
widgetId: `status-${Date.now()}`,
|
|
128
|
+
title: "Status",
|
|
129
|
+
body: chunk.statusLine,
|
|
130
|
+
variant: 'basic',
|
|
131
|
+
display: "collapsed",
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
break;
|
|
135
|
+
case 'text':
|
|
136
|
+
if (fullTextContent)
|
|
137
|
+
fullTextContent += '\n\n';
|
|
138
|
+
fullTextContent += chunk.content;
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (fullTextContent.trim()) {
|
|
79
143
|
yield agentOutput({
|
|
80
144
|
agentId: context.agentId,
|
|
81
|
-
content:
|
|
145
|
+
content: fullTextContent.trim(),
|
|
82
146
|
threadId,
|
|
83
147
|
});
|
|
84
148
|
}
|
package/dist/stream.js
CHANGED
|
@@ -11,9 +11,9 @@ export async function* streamPiPrompt(session, prompt, options) {
|
|
|
11
11
|
wake = undefined;
|
|
12
12
|
};
|
|
13
13
|
const unsubscribe = session.subscribe((event) => {
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
16
|
-
pending.push(
|
|
14
|
+
const result = formatPiEvent(event, state);
|
|
15
|
+
if (result) {
|
|
16
|
+
pending.push(result);
|
|
17
17
|
wakeUp();
|
|
18
18
|
}
|
|
19
19
|
if (event.type === 'agent_end') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meetopenbot/pi",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "OpenBot agent plugin powered by the Pi coding agent SDK.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@earendil-works/pi-ai": "^0.79.1",
|
|
23
23
|
"@earendil-works/pi-coding-agent": "^0.79.1",
|
|
24
|
-
"@meetopenbot/plugin-sdk": "^0.1.
|
|
24
|
+
"@meetopenbot/plugin-sdk": "^0.1.4"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^25.9.2",
|