@aman_asmuei/aman-agent 0.21.0 → 0.21.1
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/index.js +235 -126
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -952,135 +952,244 @@ function createClaudeCodeClient(model) {
|
|
|
952
952
|
}
|
|
953
953
|
|
|
954
954
|
// src/llm/copilot.ts
|
|
955
|
-
import
|
|
956
|
-
|
|
957
|
-
var GITHUB_MODELS_BASE_URL = "https://models.inference.ai.azure.com";
|
|
958
|
-
function isGhCliInstalled() {
|
|
955
|
+
import { spawn as spawn2, execFileSync as execFileSync2 } from "child_process";
|
|
956
|
+
function isCopilotCliInstalled() {
|
|
959
957
|
try {
|
|
960
|
-
execFileSync2("which", ["
|
|
958
|
+
execFileSync2("which", ["copilot"], { stdio: "ignore" });
|
|
961
959
|
return true;
|
|
962
960
|
} catch {
|
|
963
961
|
return false;
|
|
964
962
|
}
|
|
965
963
|
}
|
|
966
|
-
function
|
|
964
|
+
function isCopilotCliAuthenticated() {
|
|
967
965
|
try {
|
|
968
|
-
const result = execFileSync2("
|
|
969
|
-
stdio: ["ignore", "pipe", "
|
|
966
|
+
const result = execFileSync2("copilot", ["--version"], {
|
|
967
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
970
968
|
timeout: 5e3
|
|
971
969
|
});
|
|
972
|
-
return
|
|
970
|
+
return result.toString().trim().length > 0;
|
|
973
971
|
} catch {
|
|
974
972
|
return false;
|
|
975
973
|
}
|
|
976
974
|
}
|
|
977
|
-
function
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
if (
|
|
984
|
-
|
|
975
|
+
function extractText2(content) {
|
|
976
|
+
if (typeof content === "string") return content;
|
|
977
|
+
return content.map((block) => {
|
|
978
|
+
if (block.type === "text") return block.text;
|
|
979
|
+
if (block.type === "tool_result")
|
|
980
|
+
return `[Tool result for ${block.tool_use_id}]: ${block.content}`;
|
|
981
|
+
if (block.type === "tool_use") return `[Used tool: ${block.name}]`;
|
|
982
|
+
return "";
|
|
983
|
+
}).filter(Boolean).join("\n");
|
|
984
|
+
}
|
|
985
|
+
function formatConversation2(systemPrompt, messages, tools) {
|
|
986
|
+
const parts = [];
|
|
987
|
+
let fullSystem = systemPrompt;
|
|
988
|
+
if (tools && tools.length > 0) {
|
|
989
|
+
fullSystem += "\n\n## Available Tools\n";
|
|
990
|
+
fullSystem += "You have access to the following tools. To use a tool, respond with a JSON block in this exact format:\n";
|
|
991
|
+
fullSystem += '```json\n{"tool_use": {"id": "call_1", "name": "tool_name", "input": {\u2026}}}\n```\n\n';
|
|
992
|
+
for (const tool of tools) {
|
|
993
|
+
fullSystem += `### ${tool.name}
|
|
994
|
+
${tool.description}
|
|
995
|
+
Parameters: ${JSON.stringify(tool.input_schema)}
|
|
996
|
+
|
|
997
|
+
`;
|
|
998
|
+
}
|
|
999
|
+
fullSystem += "You may include multiple tool_use blocks. After each tool use, you will receive the result and can continue.\n";
|
|
1000
|
+
}
|
|
1001
|
+
if (messages.length > 1) {
|
|
1002
|
+
parts.push("<conversation_history>");
|
|
1003
|
+
for (let i = 0; i < messages.length - 1; i++) {
|
|
1004
|
+
const msg = messages[i];
|
|
1005
|
+
const role = msg.role === "user" ? "User" : "Assistant";
|
|
1006
|
+
const text3 = extractText2(msg.content);
|
|
1007
|
+
parts.push(`[${role}]: ${text3}`);
|
|
1008
|
+
}
|
|
1009
|
+
parts.push("</conversation_history>\n");
|
|
1010
|
+
}
|
|
1011
|
+
const lastMsg = messages[messages.length - 1];
|
|
1012
|
+
if (lastMsg) {
|
|
1013
|
+
parts.push(extractText2(lastMsg.content));
|
|
1014
|
+
}
|
|
1015
|
+
return { prompt: parts.join("\n"), systemPrompt: fullSystem };
|
|
1016
|
+
}
|
|
1017
|
+
function parseToolUses2(text3) {
|
|
1018
|
+
const toolUses = [];
|
|
1019
|
+
const codeBlockRegex = /```json\s*\n?([\s\S]*?)```/g;
|
|
1020
|
+
let match;
|
|
1021
|
+
while ((match = codeBlockRegex.exec(text3)) !== null) {
|
|
1022
|
+
try {
|
|
1023
|
+
const parsed = JSON.parse(match[1].trim());
|
|
1024
|
+
if (parsed.tool_use) {
|
|
1025
|
+
toolUses.push({
|
|
1026
|
+
id: parsed.tool_use.id || `call_${toolUses.length + 1}`,
|
|
1027
|
+
name: parsed.tool_use.name,
|
|
1028
|
+
input: parsed.tool_use.input || {}
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
} catch {
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
if (toolUses.length === 0) {
|
|
1035
|
+
const inlineRegex = /\{"tool_use"\s*:\s*\{[^}]*"name"\s*:\s*"[^"]+?"[^}]*\}\s*\}/g;
|
|
1036
|
+
while ((match = inlineRegex.exec(text3)) !== null) {
|
|
1037
|
+
try {
|
|
1038
|
+
const parsed = JSON.parse(match[0]);
|
|
1039
|
+
if (parsed.tool_use) {
|
|
1040
|
+
toolUses.push({
|
|
1041
|
+
id: parsed.tool_use.id || `call_${toolUses.length + 1}`,
|
|
1042
|
+
name: parsed.tool_use.name,
|
|
1043
|
+
input: parsed.tool_use.input || {}
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
} catch {
|
|
1047
|
+
}
|
|
985
1048
|
}
|
|
986
|
-
return token;
|
|
987
|
-
} catch {
|
|
988
|
-
throw new Error(
|
|
989
|
-
"Failed to get GitHub token. Run: gh auth login"
|
|
990
|
-
);
|
|
991
1049
|
}
|
|
1050
|
+
return toolUses;
|
|
992
1051
|
}
|
|
993
1052
|
function createCopilotClient(model) {
|
|
994
1053
|
return {
|
|
995
1054
|
async chat(systemPrompt, messages, onChunk, tools, options) {
|
|
996
|
-
const
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1055
|
+
const { prompt, systemPrompt: fullSystem } = formatConversation2(
|
|
1056
|
+
systemPrompt,
|
|
1057
|
+
messages,
|
|
1058
|
+
tools
|
|
1059
|
+
);
|
|
1060
|
+
return new Promise((resolve, reject) => {
|
|
1061
|
+
const args = [
|
|
1062
|
+
"--print",
|
|
1063
|
+
"--output-format",
|
|
1064
|
+
"json",
|
|
1065
|
+
"--silent",
|
|
1066
|
+
"--no-custom-instructions"
|
|
1067
|
+
];
|
|
1068
|
+
if (model) {
|
|
1069
|
+
args.push("--model", model);
|
|
1070
|
+
}
|
|
1071
|
+
args.push(prompt);
|
|
1072
|
+
const proc = spawn2("copilot", args, {
|
|
1073
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1074
|
+
env: {
|
|
1075
|
+
...process.env,
|
|
1076
|
+
COPILOT_SYSTEM_PROMPT: fullSystem
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1004
1079
|
let fullText = "";
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1080
|
+
let buffer = "";
|
|
1081
|
+
let stderrOutput = "";
|
|
1082
|
+
proc.stdout.on("data", (data) => {
|
|
1083
|
+
buffer += data.toString();
|
|
1084
|
+
const lines = buffer.split("\n");
|
|
1085
|
+
buffer = lines.pop() || "";
|
|
1086
|
+
for (const line of lines) {
|
|
1087
|
+
if (!line.trim()) continue;
|
|
1088
|
+
try {
|
|
1089
|
+
const event = JSON.parse(line);
|
|
1090
|
+
if (event.type === "assistant" && event.content) {
|
|
1091
|
+
fullText += event.content;
|
|
1092
|
+
onChunk({ type: "text", text: event.content });
|
|
1093
|
+
} else if (event.type === "message" && event.message?.content) {
|
|
1094
|
+
for (const block of event.message.content) {
|
|
1095
|
+
if (block.type === "text" && block.text) {
|
|
1096
|
+
fullText += block.text;
|
|
1097
|
+
onChunk({ type: "text", text: block.text });
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
} else if (event.type === "content_block_delta") {
|
|
1101
|
+
if (event.delta?.type === "text_delta" && event.delta.text) {
|
|
1102
|
+
fullText += event.delta.text;
|
|
1103
|
+
onChunk({ type: "text", text: event.delta.text });
|
|
1104
|
+
}
|
|
1105
|
+
} else if (event.role === "assistant" && event.content) {
|
|
1106
|
+
const text3 = typeof event.content === "string" ? event.content : event.content.map((b) => b.text || "").join("");
|
|
1107
|
+
if (text3) {
|
|
1108
|
+
fullText += text3;
|
|
1109
|
+
onChunk({ type: "text", text: text3 });
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
} catch {
|
|
1113
|
+
if (line.trim()) {
|
|
1114
|
+
fullText += line;
|
|
1115
|
+
onChunk({ type: "text", text: line });
|
|
1116
|
+
}
|
|
1019
1117
|
}
|
|
1020
|
-
}));
|
|
1021
|
-
}
|
|
1022
|
-
const stream = await client.chat.completions.create(
|
|
1023
|
-
createParams
|
|
1024
|
-
);
|
|
1025
|
-
for await (const chunk of stream) {
|
|
1026
|
-
const delta = chunk.choices[0]?.delta;
|
|
1027
|
-
if (!delta) continue;
|
|
1028
|
-
if (delta.content) {
|
|
1029
|
-
fullText += delta.content;
|
|
1030
|
-
onChunk({ type: "text", text: delta.content });
|
|
1031
1118
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1119
|
+
});
|
|
1120
|
+
proc.stderr.on("data", (data) => {
|
|
1121
|
+
stderrOutput += data.toString();
|
|
1122
|
+
});
|
|
1123
|
+
proc.on("close", (code) => {
|
|
1124
|
+
if (buffer.trim()) {
|
|
1125
|
+
try {
|
|
1126
|
+
const event = JSON.parse(buffer);
|
|
1127
|
+
if (event.type === "assistant" && event.content) {
|
|
1128
|
+
fullText += event.content;
|
|
1129
|
+
onChunk({ type: "text", text: event.content });
|
|
1130
|
+
} else if (event.role === "assistant" && typeof event.content === "string") {
|
|
1131
|
+
fullText += event.content;
|
|
1132
|
+
onChunk({ type: "text", text: event.content });
|
|
1133
|
+
}
|
|
1134
|
+
} catch {
|
|
1135
|
+
if (buffer.trim()) {
|
|
1136
|
+
fullText += buffer;
|
|
1137
|
+
onChunk({ type: "text", text: buffer });
|
|
1039
1138
|
}
|
|
1040
|
-
if (tc.id) acc.id = tc.id;
|
|
1041
|
-
if (tc.function?.name) acc.name = tc.function.name;
|
|
1042
|
-
if (tc.function?.arguments) acc.arguments += tc.function.arguments;
|
|
1043
1139
|
}
|
|
1044
1140
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1141
|
+
onChunk({ type: "done" });
|
|
1142
|
+
if (code !== 0 && !fullText) {
|
|
1143
|
+
reject(
|
|
1144
|
+
new Error(
|
|
1145
|
+
`Copilot CLI exited with code ${code}${stderrOutput ? `: ${stderrOutput.trim()}` : ""}`
|
|
1146
|
+
)
|
|
1147
|
+
);
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
const hasTools = tools && tools.length > 0;
|
|
1151
|
+
if (hasTools) {
|
|
1152
|
+
const toolUses = parseToolUses2(fullText);
|
|
1153
|
+
if (toolUses.length > 0) {
|
|
1154
|
+
let cleanText = fullText;
|
|
1155
|
+
const stripRegex = /```json\s*\n?\s*\{"tool_use"[\s\S]*?```/g;
|
|
1156
|
+
cleanText = cleanText.replace(stripRegex, "").trim();
|
|
1157
|
+
const contentBlocks = [];
|
|
1158
|
+
if (cleanText) {
|
|
1159
|
+
contentBlocks.push({ type: "text", text: cleanText });
|
|
1160
|
+
}
|
|
1161
|
+
for (const tu of toolUses) {
|
|
1162
|
+
contentBlocks.push({
|
|
1163
|
+
type: "tool_use",
|
|
1164
|
+
id: tu.id,
|
|
1165
|
+
name: tu.name,
|
|
1166
|
+
input: tu.input
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
resolve({
|
|
1170
|
+
message: { role: "assistant", content: contentBlocks },
|
|
1171
|
+
toolUses
|
|
1172
|
+
});
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
resolve({
|
|
1177
|
+
message: { role: "assistant", content: fullText },
|
|
1178
|
+
toolUses: []
|
|
1179
|
+
});
|
|
1180
|
+
});
|
|
1181
|
+
proc.on("error", (err) => {
|
|
1182
|
+
if (err.code === "ENOENT") {
|
|
1183
|
+
reject(
|
|
1184
|
+
new Error(
|
|
1185
|
+
"Copilot CLI not found. Install it from: https://docs.github.com/copilot/how-tos/copilot-cli"
|
|
1186
|
+
)
|
|
1187
|
+
);
|
|
1188
|
+
} else {
|
|
1189
|
+
reject(err);
|
|
1190
|
+
}
|
|
1191
|
+
});
|
|
1192
|
+
});
|
|
1084
1193
|
}
|
|
1085
1194
|
};
|
|
1086
1195
|
}
|
|
@@ -3914,7 +4023,7 @@ function handleReset(action) {
|
|
|
3914
4023
|
function handleUpdate() {
|
|
3915
4024
|
try {
|
|
3916
4025
|
const current = execFileSync3("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
|
|
3917
|
-
const local = true ? "0.21.
|
|
4026
|
+
const local = true ? "0.21.1" : "unknown";
|
|
3918
4027
|
if (current === local) {
|
|
3919
4028
|
return { handled: true, output: `${pc5.green("Up to date")} \u2014 v${local}` };
|
|
3920
4029
|
}
|
|
@@ -6369,7 +6478,7 @@ function bootstrapEcosystem() {
|
|
|
6369
6478
|
return true;
|
|
6370
6479
|
}
|
|
6371
6480
|
var program = new Command();
|
|
6372
|
-
program.name("aman-agent").description("Your AI companion, running locally").version("0.21.
|
|
6481
|
+
program.name("aman-agent").description("Your AI companion, running locally").version("0.21.1").option("--model <model>", "Override LLM model").option("--budget <tokens>", "Token budget for system prompt (default: 8000)", parseInt).option("--profile <name>", "Use a specific agent profile (e.g., coder, writer, researcher)").action(async (options) => {
|
|
6373
6482
|
p3.intro(pc8.bold("aman agent") + pc8.dim(" \u2014 your AI companion"));
|
|
6374
6483
|
let config = loadConfig();
|
|
6375
6484
|
if (!config) {
|
|
@@ -6491,68 +6600,68 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
|
|
|
6491
6600
|
` ${pc8.cyan("Business")} $19/user/mo Team admin + policy controls`,
|
|
6492
6601
|
` ${pc8.cyan("Enterprise")} $39/user/mo SSO, audit logs, IP indemnity`,
|
|
6493
6602
|
"",
|
|
6494
|
-
`${pc8.dim("Authentication is handled by the
|
|
6603
|
+
`${pc8.dim("Authentication is handled by the Copilot CLI.")}`,
|
|
6495
6604
|
`${pc8.dim("Subscribe at: https://github.com/features/copilot")}`
|
|
6496
6605
|
].join("\n"),
|
|
6497
6606
|
"Copilot Plans"
|
|
6498
6607
|
);
|
|
6499
|
-
if (!
|
|
6500
|
-
p3.log.error("
|
|
6608
|
+
if (!isCopilotCliInstalled()) {
|
|
6609
|
+
p3.log.error("Copilot CLI is not installed.");
|
|
6501
6610
|
p3.log.info("Install it from:");
|
|
6502
|
-
p3.log.step(pc8.bold("https://
|
|
6611
|
+
p3.log.step(pc8.bold("https://docs.github.com/copilot/how-tos/copilot-cli"));
|
|
6503
6612
|
p3.log.info(pc8.dim("Then re-run aman-agent to continue setup."));
|
|
6504
6613
|
process.exit(1);
|
|
6505
6614
|
}
|
|
6506
|
-
p3.log.success("
|
|
6507
|
-
const
|
|
6508
|
-
if (
|
|
6509
|
-
p3.log.success("
|
|
6615
|
+
p3.log.success("Copilot CLI detected.");
|
|
6616
|
+
const copilotAuth = isCopilotCliAuthenticated();
|
|
6617
|
+
if (copilotAuth) {
|
|
6618
|
+
p3.log.success("Copilot authentication found.");
|
|
6510
6619
|
} else {
|
|
6511
|
-
p3.log.warn("Not logged in to
|
|
6620
|
+
p3.log.warn("Not logged in to Copilot.");
|
|
6512
6621
|
const authAction = await p3.select({
|
|
6513
6622
|
message: "Authentication",
|
|
6514
6623
|
options: [
|
|
6515
|
-
{ value: "login", label: "Log in now", hint: "runs:
|
|
6624
|
+
{ value: "login", label: "Log in now", hint: "runs: copilot login" },
|
|
6516
6625
|
{ value: "skip", label: "Skip (I'll log in later)" }
|
|
6517
6626
|
]
|
|
6518
6627
|
});
|
|
6519
6628
|
if (p3.isCancel(authAction)) process.exit(0);
|
|
6520
6629
|
if (authAction === "login") {
|
|
6521
|
-
p3.log.step("Launching
|
|
6630
|
+
p3.log.step("Launching Copilot login...");
|
|
6522
6631
|
const { spawnSync } = await import("child_process");
|
|
6523
|
-
const loginResult = spawnSync("
|
|
6632
|
+
const loginResult = spawnSync("copilot", ["login"], {
|
|
6524
6633
|
stdio: "inherit"
|
|
6525
6634
|
});
|
|
6526
6635
|
if (loginResult.status !== 0) {
|
|
6527
6636
|
p3.log.error("Login failed or was cancelled.");
|
|
6528
6637
|
process.exit(1);
|
|
6529
6638
|
}
|
|
6530
|
-
p3.log.success("
|
|
6639
|
+
p3.log.success("Copilot login successful.");
|
|
6531
6640
|
}
|
|
6532
6641
|
}
|
|
6533
6642
|
apiKey = "copilot";
|
|
6534
6643
|
const modelChoice = await p3.select({
|
|
6535
6644
|
message: "Model",
|
|
6536
6645
|
options: [
|
|
6537
|
-
{ value: "
|
|
6538
|
-
{ value: "gpt-4o
|
|
6646
|
+
{ value: "default", label: "Default", hint: "Copilot's default model" },
|
|
6647
|
+
{ value: "gpt-4o", label: "GPT-4o", hint: "fast" },
|
|
6648
|
+
{ value: "gpt-5.2", label: "GPT-5.2", hint: "most capable" },
|
|
6539
6649
|
{ value: "o3-mini", label: "o3-mini", hint: "reasoning" },
|
|
6540
|
-
{ value: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", hint: "via GitHub Models" },
|
|
6541
|
-
{ value: "meta-llama-3.1-405b-instruct", label: "Llama 3.1 405B", hint: "open source" },
|
|
6542
|
-
{ value: "mistral-large-2411", label: "Mistral Large", hint: "open source" },
|
|
6543
6650
|
{ value: "custom", label: "Custom model ID" }
|
|
6544
6651
|
],
|
|
6545
|
-
initialValue: "
|
|
6652
|
+
initialValue: "default"
|
|
6546
6653
|
});
|
|
6547
6654
|
if (p3.isCancel(modelChoice)) process.exit(0);
|
|
6548
6655
|
if (modelChoice === "custom") {
|
|
6549
6656
|
const customModel = await p3.text({
|
|
6550
|
-
message: "Model ID",
|
|
6657
|
+
message: "Model ID (run copilot --help for available models)",
|
|
6551
6658
|
placeholder: "gpt-4o",
|
|
6552
6659
|
validate: (v) => v.length === 0 ? "Model ID is required" : void 0
|
|
6553
6660
|
});
|
|
6554
6661
|
if (p3.isCancel(customModel)) process.exit(0);
|
|
6555
6662
|
defaultModel = customModel;
|
|
6663
|
+
} else if (modelChoice === "default") {
|
|
6664
|
+
defaultModel = "";
|
|
6556
6665
|
} else {
|
|
6557
6666
|
defaultModel = modelChoice;
|
|
6558
6667
|
}
|