@buyong/pi-devin 0.1.4 → 0.1.6
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.ko.md +222 -0
- package/README.md +37 -41
- package/index.ts +6 -12
- package/package.json +4 -1
- package/src/core/auth/access.ts +7 -3
- package/src/core/auth/callback-server.ts +57 -0
- package/src/core/auth/index.ts +2 -1
- package/src/core/auth/login.ts +104 -151
- package/src/core/auth/pkce.ts +32 -0
- package/src/core/auth/rest-exchange.ts +32 -30
- package/src/core/cancellation.ts +99 -0
- package/src/core/client.ts +127 -122
- package/src/core/errors.ts +115 -0
- package/src/core/index.ts +18 -4
- package/src/core/inference/accumulator.ts +174 -0
- package/src/core/inference/images.ts +22 -15
- package/src/core/inference/request.ts +59 -0
- package/src/core/inference/retry.ts +31 -31
- package/src/core/inference/state.ts +7 -3
- package/src/core/inference/stream-chat.ts +48 -0
- package/src/core/models/access.ts +4 -3
- package/src/core/models/catalog.ts +29 -20
- package/src/core/models/select.ts +14 -12
- package/src/core/models/variants.ts +85 -72
- package/src/core/protocol/connect-client.ts +288 -0
- package/src/core/protocol/device.ts +33 -34
- package/src/core/protocol/endpoint.ts +22 -0
- package/src/core/protocol/fingerprint.ts +38 -26
- package/src/core/protocol/frames.ts +101 -0
- package/src/core/protocol/http/fetch-client.ts +42 -0
- package/src/core/protocol/http/node-client.ts +130 -0
- package/src/core/protocol/http/response.ts +99 -0
- package/src/core/protocol/http.ts +41 -101
- package/src/core/protocol/protobuf.ts +93 -74
- package/src/core/redaction.ts +33 -0
- package/src/core/services/device-identity.ts +15 -0
- package/src/core/services/http-transport.ts +28 -0
- package/src/core/services/platform.ts +54 -0
- package/src/core/types.ts +2 -23
- package/src/core/validation.ts +25 -0
- package/src/pi/adapters/pi/devin-command.ts +82 -0
- package/src/pi/adapters/pi/fusion-command.ts +92 -0
- package/src/pi/adapters/pi/oauth.ts +14 -0
- package/src/pi/adapters/pi/provider.ts +22 -0
- package/src/pi/adapters/pi/registration.ts +89 -0
- package/src/pi/adapters/pi/response-stream.ts +164 -0
- package/src/pi/adapters/pi/sidekick-tool.ts +45 -0
- package/src/pi/adapters/pi/transcript.ts +177 -0
- package/src/pi/adapters/pi/types.ts +14 -0
- package/src/pi/{devin-panel.ts → adapters/pi/ui/devin-panel.ts} +11 -9
- package/src/pi/{fusion-picker.ts → adapters/pi/ui/fusion-picker.ts} +1 -1
- package/src/pi/adapters/pi/usage-status.ts +65 -0
- package/src/pi/adapters/storage/files.ts +66 -0
- package/src/pi/adapters/storage/json-file.ts +31 -0
- package/src/pi/app/config.ts +25 -0
- package/src/pi/app/environment.ts +30 -0
- package/src/pi/app/layer.ts +43 -0
- package/src/pi/app/runtime.ts +20 -0
- package/src/pi/app/session.ts +26 -0
- package/src/pi/features/accounts/service.ts +69 -0
- package/src/pi/features/accounts/types.ts +25 -0
- package/src/pi/features/auth/credential.ts +40 -0
- package/src/pi/features/auth/guard.ts +25 -0
- package/src/pi/features/auth/login.ts +116 -0
- package/src/pi/features/auth/state.ts +48 -0
- package/src/pi/features/auth/types.ts +36 -0
- package/src/pi/features/bounded.ts +4 -0
- package/src/pi/features/catalog/constants.ts +10 -0
- package/src/pi/features/catalog/fusion.ts +45 -0
- package/src/pi/features/catalog/ids.ts +79 -0
- package/src/pi/features/catalog/projection.ts +93 -0
- package/src/pi/features/catalog/remote.ts +15 -0
- package/src/pi/features/catalog/restore.ts +53 -0
- package/src/pi/features/catalog/service.ts +158 -0
- package/src/pi/features/catalog/types.ts +56 -0
- package/src/pi/features/clients/service.ts +47 -0
- package/src/pi/features/clients/types.ts +22 -0
- package/src/pi/features/default-scheduler.ts +12 -0
- package/src/pi/features/inference/request.ts +190 -0
- package/src/pi/features/inference/service.ts +33 -0
- package/src/pi/features/inference/types.ts +11 -0
- package/src/pi/features/lifetime/service.ts +19 -0
- package/src/pi/features/lifetime/types.ts +13 -0
- package/src/pi/features/runs/admission.ts +36 -0
- package/src/pi/features/runs/lifecycle.ts +207 -0
- package/src/pi/features/runs/service.ts +10 -0
- package/src/pi/features/runs/state.ts +37 -0
- package/src/pi/features/runs/types.ts +43 -0
- package/src/pi/features/settings/service.ts +46 -0
- package/src/pi/features/settings/types.ts +36 -0
- package/src/pi/features/sidekick/child.ts +228 -0
- package/src/pi/features/sidekick/command.ts +80 -0
- package/src/pi/features/sidekick/launcher.ts +12 -0
- package/src/pi/features/sidekick/prompts.ts +17 -0
- package/src/pi/features/sidekick/report.ts +51 -0
- package/src/pi/features/sidekick/service.ts +176 -0
- package/src/pi/features/sidekick/types.ts +99 -0
- package/src/pi/features/usage/changes.ts +20 -0
- package/src/pi/{usage.ts → features/usage/report.ts} +3 -34
- package/src/pi/features/usage/types.ts +33 -0
- package/src/core/inference/chat.ts +0 -234
- package/src/core/protocol/transport.ts +0 -513
- package/src/pi/auth.ts +0 -145
- package/src/pi/devin-command.ts +0 -76
- package/src/pi/devin-settings.ts +0 -50
- package/src/pi/extension.ts +0 -80
- package/src/pi/fusion-command.ts +0 -83
- package/src/pi/fusion-settings.ts +0 -44
- package/src/pi/lifecycle.ts +0 -217
- package/src/pi/messages.ts +0 -131
- package/src/pi/models.ts +0 -379
- package/src/pi/provider.ts +0 -249
- package/src/pi/sidekick-report.ts +0 -47
- package/src/pi/sidekick-runtime.ts +0 -300
- package/src/pi/sidekick.ts +0 -211
- package/src/pi/stream.ts +0 -124
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { object, requiredString, tokenCount, type ChatMessage, type ChatResult, type ChatTool, type ImageData, type JsonObject, type ToolCall, type Usage } from "../types.ts";
|
|
3
|
-
import type { ConnectClient } from "../protocol/transport.ts";
|
|
4
|
-
import { CHAT_METHOD } from "../protocol/protobuf.ts";
|
|
5
|
-
import { wireMessages } from "./messages.ts";
|
|
6
|
-
|
|
7
|
-
export const DEFAULT_SYSTEM_PROMPT = "You are a helpful assistant. Follow the user\'s request concisely.";
|
|
8
|
-
|
|
9
|
-
export function userMessage(prompt: string, images: readonly ImageData[] = []): ChatMessage {
|
|
10
|
-
return {
|
|
11
|
-
messageId: randomUUID(), source: "CHAT_MESSAGE_SOURCE_USER", prompt,
|
|
12
|
-
...(images.length ? { images: images.map((image) => ({ ...image })) } : {}),
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function chatRequest(options: {
|
|
17
|
-
metadata: JsonObject;
|
|
18
|
-
model: string;
|
|
19
|
-
messages: ChatMessage[];
|
|
20
|
-
systemPrompt: string;
|
|
21
|
-
maxTokens: number;
|
|
22
|
-
cascadeId: string;
|
|
23
|
-
trajectoryId: string;
|
|
24
|
-
executionId?: string;
|
|
25
|
-
clientSessionId?: string;
|
|
26
|
-
modelAssignmentJwt?: string;
|
|
27
|
-
stepIndex?: number;
|
|
28
|
-
isAuxiliary?: boolean;
|
|
29
|
-
isRecovery?: boolean;
|
|
30
|
-
includeContext?: boolean;
|
|
31
|
-
cwd?: string;
|
|
32
|
-
tools?: ChatTool[];
|
|
33
|
-
}): JsonObject {
|
|
34
|
-
return {
|
|
35
|
-
metadata: options.metadata,
|
|
36
|
-
prompt: options.systemPrompt,
|
|
37
|
-
chatMessagePrompts: wireMessages(options.messages, { includeContext: options.includeContext, cwd: options.cwd }),
|
|
38
|
-
chatModelUid: options.model,
|
|
39
|
-
requestType: "CHAT_MESSAGE_REQUEST_TYPE_CASCADE",
|
|
40
|
-
configuration: {
|
|
41
|
-
maxTokens: options.maxTokens,
|
|
42
|
-
numCompletions: 1,
|
|
43
|
-
maxNewlines: 400,
|
|
44
|
-
temperature: 1,
|
|
45
|
-
topK: 40,
|
|
46
|
-
topP: Math.fround(0.95),
|
|
47
|
-
},
|
|
48
|
-
trajectoryReference: {
|
|
49
|
-
trajectoryId: options.trajectoryId,
|
|
50
|
-
trajectoryType: "CORTEX_TRAJECTORY_TYPE_CASCADE",
|
|
51
|
-
...(!options.isAuxiliary && !options.isRecovery && options.messages.at(-1)?.source === "CHAT_MESSAGE_SOURCE_USER" ? { stepType: "CORTEX_STEP_TYPE_USER_INPUT" } : {}),
|
|
52
|
-
...(options.stepIndex ? { stepIndex: options.stepIndex } : {}),
|
|
53
|
-
},
|
|
54
|
-
cascadeId: options.cascadeId,
|
|
55
|
-
plannerMode: "CONVERSATIONAL_PLANNER_MODE_DEFAULT",
|
|
56
|
-
...(!options.isAuxiliary && options.executionId ? { executionId: options.executionId } : {}),
|
|
57
|
-
...(options.clientSessionId ? { clientSessionId: options.clientSessionId } : {}),
|
|
58
|
-
...(options.modelAssignmentJwt ? { modelAssignmentJwt: options.modelAssignmentJwt } : {}),
|
|
59
|
-
...(options.tools?.length ? { tools: options.tools } : {}),
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Backends mark a finished turn differently: Anthropic text ends with MIN_LOG_PROB, Gemini tool calls with STOP_PATTERN,
|
|
64
|
-
// and OpenAI sends no stop reason (UNSPECIFIED is the proto3 default, so it is not on the wire).
|
|
65
|
-
const COMPLETE_STOP_REASONS = new Set(["STOP_REASON_STOP_PATTERN", "STOP_REASON_FUNCTION_CALL", "STOP_REASON_MIN_LOG_PROB", "STOP_REASON_UNSPECIFIED", ""]);
|
|
66
|
-
|
|
67
|
-
/** Attaches argument deltas without an ID to the call that started with the first ID. Ambiguous parallel deltas are rejected. */
|
|
68
|
-
export class ChatAccumulator {
|
|
69
|
-
readonly message: ChatMessage = { messageId: "", source: "CHAT_MESSAGE_SOURCE_SYSTEM", prompt: "" };
|
|
70
|
-
readonly usage: Usage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0 };
|
|
71
|
-
readonly calls = new Map<string, ToolCall>();
|
|
72
|
-
private currentCall?: ToolCall;
|
|
73
|
-
private hasEnded = false;
|
|
74
|
-
private startedAt = performance.now();
|
|
75
|
-
private firstDeltaMs?: number;
|
|
76
|
-
private stopReason = "";
|
|
77
|
-
private usageReported = false;
|
|
78
|
-
private frameCount = 0;
|
|
79
|
-
private stopFrameIndex?: number;
|
|
80
|
-
private lastUsageFrameIndex?: number;
|
|
81
|
-
private idlessToolDeltaCount = 0;
|
|
82
|
-
private actualModelUid?: string;
|
|
83
|
-
private usageModelUid?: string;
|
|
84
|
-
|
|
85
|
-
accept(data: JsonObject, isEnd = false): void {
|
|
86
|
-
if (this.hasEnded) throw new Error("Cannot accumulate a response after EndStream.");
|
|
87
|
-
this.frameCount++;
|
|
88
|
-
if (isEnd) {
|
|
89
|
-
if (data.error) throw new Error("An error EndStream cannot be treated as success.");
|
|
90
|
-
this.hasEnded = true;
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if (data.redact === true) throw new Error("The server redacted the response.");
|
|
94
|
-
if (typeof data.messageId === "string" && data.messageId) this.message.messageId = data.messageId;
|
|
95
|
-
if (data.thinkingRedacted === true) {
|
|
96
|
-
this.message.thinkingRedacted = true;
|
|
97
|
-
this.message.thinking = "";
|
|
98
|
-
}
|
|
99
|
-
if (typeof data.deltaText === "string") this.message.prompt += data.deltaText;
|
|
100
|
-
if (typeof data.deltaThinking === "string" && !this.message.thinkingRedacted) {
|
|
101
|
-
this.message.thinking = (this.message.thinking ?? "") + data.deltaThinking;
|
|
102
|
-
}
|
|
103
|
-
if (typeof data.deltaSignature === "string") this.message.signature = (this.message.signature ?? "") + data.deltaSignature;
|
|
104
|
-
for (const [source, target] of [
|
|
105
|
-
["deltaSignatureType", "signatureType"], ["geminiThoughtSignature", "geminiThoughtSignature"],
|
|
106
|
-
["outputId", "outputId"], ["thinkingId", "thinkingId"], ["phase", "phase"],
|
|
107
|
-
] as const) {
|
|
108
|
-
if (typeof data[source] === "string") this.message[target] = data[source];
|
|
109
|
-
}
|
|
110
|
-
if (typeof data.actualModelUid === "string") this.actualModelUid = data.actualModelUid;
|
|
111
|
-
if (data.deltaToolCalls !== undefined) {
|
|
112
|
-
if (!Array.isArray(data.deltaToolCalls)) throw new Error("deltaToolCalls must be an array.");
|
|
113
|
-
for (const value of data.deltaToolCalls) {
|
|
114
|
-
const delta = object(value, "tool delta");
|
|
115
|
-
const id = typeof delta.id === "string" && delta.id ? delta.id : undefined;
|
|
116
|
-
if (id) {
|
|
117
|
-
let call = this.calls.get(id);
|
|
118
|
-
if (!call) {
|
|
119
|
-
call = { id, name: "", argumentsJson: "" };
|
|
120
|
-
this.calls.set(id, call);
|
|
121
|
-
}
|
|
122
|
-
this.currentCall = call;
|
|
123
|
-
} else {
|
|
124
|
-
this.idlessToolDeltaCount++;
|
|
125
|
-
if (data.deltaToolCalls.length !== 1 || !this.currentCall || this.calls.size > 1) {
|
|
126
|
-
throw new Error("Cannot attach a delta without a tool ID to a specific call.");
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
const call = this.currentCall!;
|
|
130
|
-
if (delta.isCustomToolCall) throw new Error("Grammar-based custom tools are not supported.");
|
|
131
|
-
if (delta.invalidJsonErr || delta.invalidJsonStr) throw new Error("The server reported a tool argument JSON error.");
|
|
132
|
-
if (typeof delta.name === "string") call.name += delta.name;
|
|
133
|
-
if (typeof delta.argumentsJson === "string") call.argumentsJson += delta.argumentsJson;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
if (data.deltaText || data.deltaThinking || data.deltaToolCalls) {
|
|
137
|
-
this.firstDeltaMs ??= performance.now() - this.startedAt;
|
|
138
|
-
}
|
|
139
|
-
if (typeof data.stopReason === "string" && data.stopReason) {
|
|
140
|
-
this.stopReason = data.stopReason;
|
|
141
|
-
this.stopFrameIndex = this.frameCount;
|
|
142
|
-
}
|
|
143
|
-
if (data.usage !== undefined) {
|
|
144
|
-
const usage = object(data.usage, "usage");
|
|
145
|
-
if (typeof usage.modelUid === "string") this.usageModelUid = usage.modelUid;
|
|
146
|
-
for (const [source, target] of [
|
|
147
|
-
["inputTokens", "input"], ["outputTokens", "output"],
|
|
148
|
-
["cacheReadTokens", "cacheRead"], ["cacheWriteTokens", "cacheWrite"],
|
|
149
|
-
] as const) {
|
|
150
|
-
if (usage[source] !== undefined) {
|
|
151
|
-
this.usage[target] = tokenCount(usage[source], source);
|
|
152
|
-
this.usageReported = true;
|
|
153
|
-
this.lastUsageFrameIndex = this.frameCount;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
this.usage.totalTokens = this.usage.input + this.usage.output + this.usage.cacheRead + this.usage.cacheWrite;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
finish(): ChatResult {
|
|
161
|
-
if (!this.hasEnded) throw new Error("No successful EndStream.");
|
|
162
|
-
if (!COMPLETE_STOP_REASONS.has(this.stopReason) && this.stopReason !== "STOP_REASON_MAX_TOKENS") {
|
|
163
|
-
throw new Error(`stopReason cannot be treated as success: ${this.stopReason || "(none)"}`);
|
|
164
|
-
}
|
|
165
|
-
if (this.calls.size > 0) {
|
|
166
|
-
this.message.toolCalls = [...this.calls.values()];
|
|
167
|
-
for (const call of this.message.toolCalls) {
|
|
168
|
-
requiredString(call.name, "tool name");
|
|
169
|
-
let args: unknown;
|
|
170
|
-
try { args = JSON.parse(call.argumentsJson); }
|
|
171
|
-
catch { throw new Error(`Arguments of tool ${call.name} are not valid JSON.`); }
|
|
172
|
-
object(args, "tool arguments");
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
if (this.stopReason === "STOP_REASON_FUNCTION_CALL" && !this.calls.size) {
|
|
176
|
-
throw new Error("The response ended with FUNCTION_CALL but has no tool call.");
|
|
177
|
-
}
|
|
178
|
-
// Tool use is read from the calls themselves; only calls cut off at the output limit are rejected.
|
|
179
|
-
if (this.calls.size && !COMPLETE_STOP_REASONS.has(this.stopReason)) {
|
|
180
|
-
throw new Error("Tool calls and the stop reason do not match.");
|
|
181
|
-
}
|
|
182
|
-
this.message.messageId ||= randomUUID();
|
|
183
|
-
return {
|
|
184
|
-
message: this.message,
|
|
185
|
-
stopReason: this.stopReason,
|
|
186
|
-
usage: this.usage,
|
|
187
|
-
usageReported: this.usageReported,
|
|
188
|
-
frameCount: this.frameCount,
|
|
189
|
-
stopFrameIndex: this.stopFrameIndex,
|
|
190
|
-
lastUsageFrameIndex: this.lastUsageFrameIndex,
|
|
191
|
-
idlessToolDeltaCount: this.idlessToolDeltaCount,
|
|
192
|
-
durationMs: Math.round(performance.now() - this.startedAt),
|
|
193
|
-
firstDeltaMs: this.firstDeltaMs === undefined ? undefined : Math.round(this.firstDeltaMs),
|
|
194
|
-
actualModelUid: this.actualModelUid,
|
|
195
|
-
...(this.usageModelUid ? { usageModelUid: this.usageModelUid } : {}),
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export async function streamChat(
|
|
201
|
-
client: ConnectClient,
|
|
202
|
-
request: JsonObject,
|
|
203
|
-
options: { signal?: AbortSignal; onText?: (delta: string) => void; stage?: string; onDispatched?: () => void } = {},
|
|
204
|
-
): Promise<ChatResult> {
|
|
205
|
-
const accumulator = new ChatAccumulator();
|
|
206
|
-
for await (const frame of client.stream(CHAT_METHOD, request, options.signal, { stage: options.stage, onDispatched: options.onDispatched })) {
|
|
207
|
-
accumulator.accept(frame.data, frame.isEnd);
|
|
208
|
-
if (!frame.isEnd && typeof frame.data.deltaText === "string") options.onText?.(frame.data.deltaText);
|
|
209
|
-
}
|
|
210
|
-
const result = accumulator.finish();
|
|
211
|
-
// Field 22 records the model of the generation request, not actualModelUid/usage.modelUid.
|
|
212
|
-
if (typeof request.chatModelUid === "string") result.message.modelUid = request.chatModelUid;
|
|
213
|
-
return result;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/** Raw thinking and signatures never go to logs or reports. They are only resent inside requests. */
|
|
217
|
-
export function summarizeChat(result: ChatResult): JsonObject {
|
|
218
|
-
return {
|
|
219
|
-
text: result.message.prompt,
|
|
220
|
-
stopReason: result.stopReason,
|
|
221
|
-
usage: result.usage,
|
|
222
|
-
usageReported: result.usageReported,
|
|
223
|
-
toolCalls: result.message.toolCalls ?? [],
|
|
224
|
-
thinkingChars: result.message.thinking?.length ?? 0,
|
|
225
|
-
hasSignature: Boolean(result.message.signature || result.message.geminiThoughtSignature),
|
|
226
|
-
frameCount: result.frameCount,
|
|
227
|
-
stopFrameIndex: result.stopFrameIndex,
|
|
228
|
-
lastUsageFrameIndex: result.lastUsageFrameIndex,
|
|
229
|
-
idlessToolDeltaCount: result.idlessToolDeltaCount,
|
|
230
|
-
durationMs: result.durationMs,
|
|
231
|
-
firstDeltaMs: result.firstDeltaMs,
|
|
232
|
-
actualModelUid: result.actualModelUid,
|
|
233
|
-
};
|
|
234
|
-
}
|