@agentsky/sky 0.1.0 → 0.2.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.
|
@@ -14607,9 +14607,6 @@ var messageSchema = external_exports.object({
|
|
|
14607
14607
|
parts: external_exports.array(messagePartSchema).default([]),
|
|
14608
14608
|
metadata: external_exports.record(external_exports.string(), external_exports.unknown()).default({})
|
|
14609
14609
|
});
|
|
14610
|
-
function textParts(text) {
|
|
14611
|
-
return [{ type: "text", index: 0, text }];
|
|
14612
|
-
}
|
|
14613
14610
|
|
|
14614
14611
|
// ../../packages/spec/src/clone.ts
|
|
14615
14612
|
var CREDENTIAL_PATTERNS = [
|
|
@@ -14819,7 +14816,6 @@ var allowedLlms = {
|
|
|
14819
14816
|
"claude-opus-5",
|
|
14820
14817
|
"claude-fable-5",
|
|
14821
14818
|
"claude-sonnet-4-6",
|
|
14822
|
-
"kimi-k3",
|
|
14823
14819
|
"claude-opus-4-8"
|
|
14824
14820
|
],
|
|
14825
14821
|
codex: ["gpt-5.6-sol", "gpt-5.6-luna", "gpt-5.6-terra", "gpt-5.5"],
|
|
@@ -14948,7 +14944,6 @@ export {
|
|
|
14948
14944
|
splitMcpServers,
|
|
14949
14945
|
mcpConfigInstall,
|
|
14950
14946
|
messagePartSchema,
|
|
14951
|
-
textParts,
|
|
14952
14947
|
AGENT_TYPES,
|
|
14953
14948
|
capabilitiesSchema,
|
|
14954
14949
|
skillRefSchema,
|
package/dist/index.js
CHANGED
|
@@ -16,15 +16,19 @@ import {
|
|
|
16
16
|
mcpConfigInstall,
|
|
17
17
|
skillRefSchema,
|
|
18
18
|
splitMcpServers
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-L5LLCKZW.js";
|
|
20
20
|
import "./chunk-MLKGABMK.js";
|
|
21
21
|
|
|
22
22
|
// src/index.ts
|
|
23
|
-
import { existsSync as
|
|
23
|
+
import { existsSync as existsSync4 } from "fs";
|
|
24
24
|
import { basename as basename2, resolve as resolve3 } from "path";
|
|
25
|
-
import { createInterface as
|
|
25
|
+
import { createInterface as createInterface3 } from "readline";
|
|
26
26
|
import { Command } from "commander";
|
|
27
27
|
|
|
28
|
+
// src/version.ts
|
|
29
|
+
var CLI_VERSION = "0.2.1";
|
|
30
|
+
var USER_AGENT = `sky-cli/${CLI_VERSION} (${process.platform}; node/${process.versions.node})`;
|
|
31
|
+
|
|
28
32
|
// src/api.ts
|
|
29
33
|
var ApiError = class extends Error {
|
|
30
34
|
constructor(status, code, message) {
|
|
@@ -62,6 +66,7 @@ async function api(method, path, body, opts = {}) {
|
|
|
62
66
|
const res = await fetch(`${apiBase()}${path}`, {
|
|
63
67
|
method,
|
|
64
68
|
headers: {
|
|
69
|
+
"user-agent": USER_AGENT,
|
|
65
70
|
...opts.auth === false ? {} : authHeaders(),
|
|
66
71
|
...body !== void 0 ? { "content-type": "application/json" } : {}
|
|
67
72
|
},
|
|
@@ -70,12 +75,30 @@ async function api(method, path, body, opts = {}) {
|
|
|
70
75
|
if (!res.ok) await parseError(res);
|
|
71
76
|
return await res.json();
|
|
72
77
|
}
|
|
73
|
-
async function
|
|
74
|
-
|
|
78
|
+
async function resolveSessionRef(ref) {
|
|
79
|
+
if (ref.startsWith("sess-")) return ref;
|
|
80
|
+
const { agent: agent2 } = await api(
|
|
81
|
+
"GET",
|
|
82
|
+
`/api/v1/agents/${encodeURIComponent(ref)}`
|
|
83
|
+
).catch(async () => {
|
|
84
|
+
await api("GET", `/api/v1/sessions/${encodeURIComponent(ref)}`);
|
|
85
|
+
return { agent: { slug: ref, defaultSessionId: ref } };
|
|
86
|
+
});
|
|
87
|
+
if (!agent2.defaultSessionId) {
|
|
88
|
+
throw new ApiError(
|
|
89
|
+
404,
|
|
90
|
+
"no_sessions",
|
|
91
|
+
`agent ${agent2.slug} has no sessions \u2014 create one: sky session create ${agent2.slug}`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return agent2.defaultSessionId;
|
|
95
|
+
}
|
|
96
|
+
async function* streamEvents(sessionId, signal) {
|
|
97
|
+
const { parseSseStream } = await import("./src-Y2XOFL3Z.js");
|
|
75
98
|
const res = await fetch(
|
|
76
|
-
`${apiBase()}/api/v1/
|
|
99
|
+
`${apiBase()}/api/v1/sessions/${encodeURIComponent(sessionId)}/stream`,
|
|
77
100
|
{
|
|
78
|
-
headers: { ...authHeaders(), accept: "text/event-stream" },
|
|
101
|
+
headers: { "user-agent": USER_AGENT, ...authHeaders(), accept: "text/event-stream" },
|
|
79
102
|
signal
|
|
80
103
|
}
|
|
81
104
|
);
|
|
@@ -362,6 +385,7 @@ async function createClone(local, opts) {
|
|
|
362
385
|
throw error;
|
|
363
386
|
}
|
|
364
387
|
}
|
|
388
|
+
await api("POST", "/api/v1/sessions", { agent: created.slug });
|
|
365
389
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
366
390
|
writeLink(local.configRoot, {
|
|
367
391
|
baseUrl: apiBase(),
|
|
@@ -531,7 +555,8 @@ async function headlessLogin(verifier, challenge) {
|
|
|
531
555
|
while (Date.now() < deadline) {
|
|
532
556
|
await new Promise((r) => setTimeout(r, 3e3));
|
|
533
557
|
const res = await fetch(
|
|
534
|
-
`${apiBase()}/api/v1/cli/poll?request=${request}&verifier=${encodeURIComponent(verifier)}&clientName=${encodeURIComponent(`cli ${hostname()}`)}
|
|
558
|
+
`${apiBase()}/api/v1/cli/poll?request=${request}&verifier=${encodeURIComponent(verifier)}&clientName=${encodeURIComponent(`cli ${hostname()}`)}`,
|
|
559
|
+
{ headers: { "user-agent": USER_AGENT } }
|
|
535
560
|
);
|
|
536
561
|
if (!res.ok) {
|
|
537
562
|
const body2 = await res.json().catch(() => null);
|
|
@@ -591,16 +616,167 @@ function renderEvent(event, data) {
|
|
|
591
616
|
}
|
|
592
617
|
}
|
|
593
618
|
|
|
619
|
+
// src/subscriptions.ts
|
|
620
|
+
import { spawn as spawn3 } from "child_process";
|
|
621
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
622
|
+
import { homedir as homedir2 } from "os";
|
|
623
|
+
import { join as join2 } from "path";
|
|
624
|
+
import { createInterface as createInterface2 } from "readline";
|
|
625
|
+
var ALIASES = {
|
|
626
|
+
claude: "anthropic",
|
|
627
|
+
anthropic: "anthropic",
|
|
628
|
+
chatgpt: "openai",
|
|
629
|
+
openai: "openai",
|
|
630
|
+
codex: "openai"
|
|
631
|
+
};
|
|
632
|
+
function providerFor(name) {
|
|
633
|
+
const provider = ALIASES[name.toLowerCase()];
|
|
634
|
+
if (!provider) {
|
|
635
|
+
throw new ApiError(400, "unknown_provider", `unknown provider "${name}" \u2014 use claude or chatgpt`);
|
|
636
|
+
}
|
|
637
|
+
return provider;
|
|
638
|
+
}
|
|
639
|
+
function ask(question) {
|
|
640
|
+
return new Promise((done) => {
|
|
641
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
642
|
+
rl.question(question, (answer) => {
|
|
643
|
+
rl.close();
|
|
644
|
+
done(answer.trim());
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
function confirm2(question) {
|
|
649
|
+
return new Promise((done) => {
|
|
650
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
651
|
+
rl.question(`${question} [y/N] `, (answer) => {
|
|
652
|
+
rl.close();
|
|
653
|
+
done(/^y(es)?$/i.test(answer.trim()));
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
function mintClaudeToken() {
|
|
658
|
+
return new Promise((done) => {
|
|
659
|
+
let child;
|
|
660
|
+
try {
|
|
661
|
+
child = spawn3("claude", ["setup-token"], { stdio: ["inherit", "pipe", "inherit"] });
|
|
662
|
+
} catch {
|
|
663
|
+
done(null);
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
let buffer = "";
|
|
667
|
+
child.stdout?.on("data", (chunk) => {
|
|
668
|
+
buffer += chunk.toString();
|
|
669
|
+
process.stdout.write(chunk);
|
|
670
|
+
});
|
|
671
|
+
child.on("error", () => done(null));
|
|
672
|
+
child.on("close", () => {
|
|
673
|
+
const match = buffer.match(/sk-ant-oat[A-Za-z0-9_-]+/);
|
|
674
|
+
done(match ? match[0] : null);
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
async function put(provider, credential) {
|
|
679
|
+
const { modelSubscription } = await api(
|
|
680
|
+
"PUT",
|
|
681
|
+
`/api/v1/model-subscriptions/${provider}`,
|
|
682
|
+
{ credential }
|
|
683
|
+
);
|
|
684
|
+
return modelSubscription;
|
|
685
|
+
}
|
|
686
|
+
async function connectClaude() {
|
|
687
|
+
let token = await mintClaudeToken();
|
|
688
|
+
if (token) {
|
|
689
|
+
console.log("\nCaptured the minted token \u2014 uploading.");
|
|
690
|
+
} else {
|
|
691
|
+
console.log("Couldn't mint a token via `claude setup-token` \u2014 paste one instead.");
|
|
692
|
+
console.log("(Run `claude setup-token` on a machine with Claude Code and paste its sk-ant-oat\u2026 output.)");
|
|
693
|
+
token = await ask("Token: ");
|
|
694
|
+
}
|
|
695
|
+
if (!token) throw new ApiError(400, "no_token", "no token provided");
|
|
696
|
+
const sub = await put("anthropic", token);
|
|
697
|
+
const expiry = sub.expiresAt ? ` (expires ~${sub.expiresAt.slice(0, 10)})` : "";
|
|
698
|
+
console.log(`Connected Claude subscription${expiry}. Powers new eligible agents.`);
|
|
699
|
+
}
|
|
700
|
+
async function connectChatgpt(opts) {
|
|
701
|
+
const codexHome = process.env.CODEX_HOME || join2(homedir2(), ".codex");
|
|
702
|
+
const path = join2(codexHome, "auth.json");
|
|
703
|
+
if (!existsSync3(path)) {
|
|
704
|
+
throw new ApiError(404, "no_codex_auth", `no ${path} \u2014 run \`codex login\` first`);
|
|
705
|
+
}
|
|
706
|
+
const raw = readFileSync3(path, "utf8");
|
|
707
|
+
let accountId;
|
|
708
|
+
try {
|
|
709
|
+
const parsed = JSON.parse(raw);
|
|
710
|
+
accountId = parsed.tokens?.account_id;
|
|
711
|
+
} catch {
|
|
712
|
+
throw new ApiError(400, "invalid_codex_auth", `${path} isn't valid JSON \u2014 re-run \`codex login\``);
|
|
713
|
+
}
|
|
714
|
+
console.log(`Found Codex sign-in at ${path}${accountId ? ` (account ${accountId})` : ""}.`);
|
|
715
|
+
if (!opts.yes) {
|
|
716
|
+
const ok = await confirm2("Upload it so your cloud Codex agents run on your ChatGPT plan?");
|
|
717
|
+
if (!ok) {
|
|
718
|
+
console.log("Aborted \u2014 nothing uploaded.");
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
await put("openai", raw);
|
|
723
|
+
console.log("Connected ChatGPT plan. Powers new eligible agents.");
|
|
724
|
+
}
|
|
725
|
+
async function listSubscriptions() {
|
|
726
|
+
const { modelSubscriptions } = await api(
|
|
727
|
+
"GET",
|
|
728
|
+
"/api/v1/model-subscriptions"
|
|
729
|
+
);
|
|
730
|
+
if (modelSubscriptions.length === 0) {
|
|
731
|
+
console.log("No model subscriptions connected. Try `sky auth connect claude` or `sky auth connect chatgpt`.");
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
for (const s of modelSubscriptions) {
|
|
735
|
+
const bits = [
|
|
736
|
+
s.provider === "anthropic" ? "claude" : "chatgpt",
|
|
737
|
+
s.status,
|
|
738
|
+
s.expiresAt ? `expires ~${s.expiresAt.slice(0, 10)}` : null,
|
|
739
|
+
s.lastUsedAt ? `last used ${s.lastUsedAt.slice(0, 10)}` : null,
|
|
740
|
+
`${s.agents.length} agent${s.agents.length === 1 ? "" : "s"}`,
|
|
741
|
+
s.useForNewAgents ? "used for new agents" : "not used for new agents"
|
|
742
|
+
].filter(Boolean);
|
|
743
|
+
console.log(bits.join(" \xB7 "));
|
|
744
|
+
for (const a of s.agents) console.log(` ${a.slug ?? a.id} \u2014 ${a.name}`);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
async function disconnect(name, opts) {
|
|
748
|
+
const provider = providerFor(name);
|
|
749
|
+
const label = provider === "anthropic" ? "Claude" : "ChatGPT";
|
|
750
|
+
if (!opts.yes) {
|
|
751
|
+
const ok = await confirm2(`Disconnect ${label}? Agents running on it will fail until reconnected or switched to Platform.`);
|
|
752
|
+
if (!ok) {
|
|
753
|
+
console.log("Aborted.");
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
const { affectedAgents } = await api(
|
|
758
|
+
"DELETE",
|
|
759
|
+
`/api/v1/model-subscriptions/${provider}`
|
|
760
|
+
);
|
|
761
|
+
console.log(`Disconnected ${label}.`);
|
|
762
|
+
if (affectedAgents.length > 0) {
|
|
763
|
+
console.log(
|
|
764
|
+
`${affectedAgents.length} agent${affectedAgents.length === 1 ? "" : "s"} still point at it and will fail: ` + affectedAgents.map((a) => a.slug ?? a.id).join(", ")
|
|
765
|
+
);
|
|
766
|
+
console.log("Switch them to Platform in each agent's Configure tab (or reconnect).");
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
594
770
|
// src/index.ts
|
|
595
771
|
var program = new Command();
|
|
596
|
-
program.name("sky").description("Launch and talk to long-lived agents \u2014 agentsky.dev").version(
|
|
772
|
+
program.name("sky").description("Launch and talk to long-lived agents \u2014 agentsky.dev").version(CLI_VERSION);
|
|
597
773
|
function fail(error) {
|
|
598
774
|
if (error instanceof ApiError) console.error(`sky: ${error.message} (${error.code})`);
|
|
599
775
|
else console.error(`sky: ${error instanceof Error ? error.message : String(error)}`);
|
|
600
776
|
process.exit(1);
|
|
601
777
|
}
|
|
602
778
|
var run = (fn) => (...args) => fn(...args).catch(fail);
|
|
603
|
-
var auth = program.command("auth").description("login, logout, whoami");
|
|
779
|
+
var auth = program.command("auth").description("login, logout, whoami, model subscriptions");
|
|
604
780
|
auth.command("login").description("authorize this machine via the browser").option("--no-browser", "print a URL and poll instead of opening a browser").action(run(async (opts) => login({ noBrowser: opts.browser === false })));
|
|
605
781
|
auth.command("logout").description("forget the stored token (revoke it in Settings \u2192 API tokens)").action(
|
|
606
782
|
run(async () => {
|
|
@@ -616,6 +792,15 @@ auth.command("whoami").description("who the current token acts as").action(
|
|
|
616
792
|
);
|
|
617
793
|
})
|
|
618
794
|
);
|
|
795
|
+
auth.command("connect <provider>").description("connect a model subscription: claude (setup-token) or chatgpt (Codex sign-in)").option("-y, --yes", "skip the consent prompt").action(
|
|
796
|
+
run(async (name, opts) => {
|
|
797
|
+
const provider = providerFor(name);
|
|
798
|
+
if (provider === "anthropic") await connectClaude();
|
|
799
|
+
else await connectChatgpt(opts);
|
|
800
|
+
})
|
|
801
|
+
);
|
|
802
|
+
auth.command("accounts").description("list connected model subscriptions and the agents they power").action(run(async () => listSubscriptions()));
|
|
803
|
+
auth.command("disconnect <provider>").description("disconnect a model subscription (agents on it fail until switched)").option("-y, --yes", "skip the confirmation prompt").action(run(async (name, opts) => disconnect(name, opts)));
|
|
619
804
|
var universe = program.command("universe").description("grouping boundary for agents");
|
|
620
805
|
universe.command("list").action(
|
|
621
806
|
run(async () => {
|
|
@@ -653,8 +838,8 @@ universe.command("show").action(
|
|
|
653
838
|
}
|
|
654
839
|
})
|
|
655
840
|
);
|
|
656
|
-
var agent = program.command("agent").description("create, inspect, talk
|
|
657
|
-
agent.command("create").description("create an agent
|
|
841
|
+
var agent = program.command("agent").description("agent specs: create, inspect, talk (via the default session)");
|
|
842
|
+
agent.command("create").description("create an agent spec \u2014 no runtime; `sky session create` starts one").option("--type <type>", "hermes | claude_code | codex | openclaw").option("--llm <llm>", "model id (defaults per type)").option("--name <name>", "agent name").option("-f, --file <path>", "create from an agent.toml").action(
|
|
658
843
|
run(async (opts) => {
|
|
659
844
|
const spec = opts.file ? readAgentFile(opts.file).spec : {
|
|
660
845
|
name: opts.name ?? "My agent",
|
|
@@ -662,11 +847,9 @@ agent.command("create").description("create an agent (flags-only; bare create =
|
|
|
662
847
|
llm: opts.llm,
|
|
663
848
|
displayName: opts.name
|
|
664
849
|
};
|
|
665
|
-
if (opts.vcpus !== void 0) spec.vcpus = Number(opts.vcpus);
|
|
666
|
-
if (opts.memory !== void 0) spec.memoryMb = Number(opts.memory);
|
|
667
850
|
const { agent: created } = await api("POST", "/api/v1/agents", spec);
|
|
668
|
-
console.log(`Created ${created.slug} (${created.agentType} \xB7 ${created.llm})
|
|
669
|
-
console.log(`
|
|
851
|
+
console.log(`Created ${created.slug} (${created.agentType} \xB7 ${created.llm}) \u2014 spec only.`);
|
|
852
|
+
console.log(`Start it: sky session create ${created.slug}`);
|
|
670
853
|
})
|
|
671
854
|
);
|
|
672
855
|
agent.command("list").action(
|
|
@@ -677,8 +860,9 @@ agent.command("list").action(
|
|
|
677
860
|
return;
|
|
678
861
|
}
|
|
679
862
|
for (const a of agents) {
|
|
863
|
+
const state = a.archived ? "archived" : `${a.sessionCount} session${a.sessionCount === 1 ? "" : "s"}`;
|
|
680
864
|
console.log(
|
|
681
|
-
`${a.slug.padEnd(24)} ${a.displayName.padEnd(20)} ${a.agentType}/${a.llm} ${
|
|
865
|
+
`${a.slug.padEnd(24)} ${a.displayName.padEnd(20)} ${a.agentType}/${a.llm} ${state}`
|
|
682
866
|
);
|
|
683
867
|
}
|
|
684
868
|
})
|
|
@@ -686,36 +870,118 @@ agent.command("list").action(
|
|
|
686
870
|
agent.command("show <slug>").action(
|
|
687
871
|
run(async (slug) => {
|
|
688
872
|
const { agent: a } = await api("GET", `/api/v1/agents/${encodeURIComponent(slug)}`);
|
|
689
|
-
console.log(`${a.slug} \u2014 ${a.displayName}`);
|
|
873
|
+
console.log(`${a.slug} \u2014 ${a.displayName}${a.archived ? " (archived)" : ""}`);
|
|
690
874
|
console.log(` type ${a.agentType} \xB7 ${a.llm}`);
|
|
691
|
-
console.log(`
|
|
875
|
+
console.log(` version ${a.version}`);
|
|
876
|
+
console.log(` sessions ${a.sessionCount}`);
|
|
692
877
|
console.log(` universe ${a.universe}`);
|
|
693
878
|
if (a.capabilities.length) console.log(` caps ${a.capabilities.join(", ")}`);
|
|
694
879
|
if (a.prompt) console.log(` prompt ${a.prompt.split("\n")[0]?.slice(0, 80)}\u2026`);
|
|
695
880
|
})
|
|
696
881
|
);
|
|
697
|
-
agent.command("
|
|
882
|
+
agent.command("archive <slug>").description("retire the spec \u2014 read-only, running sessions unaffected (admin scope)").action(
|
|
883
|
+
run(async (slug) => {
|
|
884
|
+
await api("POST", `/api/v1/agents/${encodeURIComponent(slug)}/archive`);
|
|
885
|
+
console.log(`Archived ${slug} \u2014 sessions keep running; new sessions are rejected.`);
|
|
886
|
+
})
|
|
887
|
+
);
|
|
888
|
+
agent.command("destroy <slug>").description("delete the spec; requires all sessions destroyed first (admin scope)").action(
|
|
698
889
|
run(async (slug) => {
|
|
699
890
|
await api("DELETE", `/api/v1/agents/${encodeURIComponent(slug)}`);
|
|
700
891
|
console.log(`Destroyed ${slug}`);
|
|
701
892
|
})
|
|
702
893
|
);
|
|
703
|
-
agent.command("
|
|
704
|
-
run(
|
|
894
|
+
agent.command("message <slug> <text>").description("send one message to the default session and stream the turn until idle").option("--detach", "don't follow the stream; exit after the 202").action(
|
|
895
|
+
run(
|
|
896
|
+
async (slug, text, opts) => sendAndFollow(await resolveSessionRef(slug), text, Boolean(opts.detach))
|
|
897
|
+
)
|
|
898
|
+
);
|
|
899
|
+
agent.command("chat <slug>").description("interactive REPL with the default session").action(run(async (slug) => chatLoop(await resolveSessionRef(slug))));
|
|
900
|
+
var session = program.command("session").description("sessions: the running instances of an agent");
|
|
901
|
+
session.command("create <agent>").description("create a session (cheap \u2014 the pod starts on the first message)").option("--title <title>", "session title").option("--message <text>", "seed the session and start its first turn").option("--vcpus <n>", "machine vCPUs: 1, 2, 4 or 8 (default 2)").option("--memory <mb>", "machine memory in MB, 256MB steps (default 4096)").action(
|
|
902
|
+
run(async (agentRef, opts) => {
|
|
903
|
+
const { session: created } = await api("POST", "/api/v1/sessions", {
|
|
904
|
+
agent: agentRef,
|
|
905
|
+
...opts.title ? { title: opts.title } : {},
|
|
906
|
+
...opts.vcpus !== void 0 ? { vcpus: Number(opts.vcpus) } : {},
|
|
907
|
+
...opts.memory !== void 0 ? { memoryMb: Number(opts.memory) } : {},
|
|
908
|
+
...opts.message ? { initial_events: [{ type: "user.message", parts: [{ type: "text", index: 0, text: opts.message }] }] } : {}
|
|
909
|
+
});
|
|
910
|
+
console.log(`Created ${created.id} (${created.agent} \xB7 ${created.status})${created.default ? " [default]" : ""}`);
|
|
911
|
+
console.log(` sky agent message ${created.agent} "hello"`);
|
|
912
|
+
})
|
|
913
|
+
);
|
|
914
|
+
session.command("list [agent]").action(
|
|
915
|
+
run(async (agentRef) => {
|
|
916
|
+
const qs = agentRef ? `?agent=${encodeURIComponent(agentRef)}` : "";
|
|
917
|
+
const { sessions } = await api("GET", `/api/v1/sessions${qs}`);
|
|
918
|
+
if (!sessions.length) {
|
|
919
|
+
console.log("No sessions. `sky session create <agent>` to start one.");
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
for (const s of sessions) {
|
|
923
|
+
console.log(
|
|
924
|
+
`${s.id.padEnd(24)} ${(s.agent ?? "-").padEnd(20)} ${(s.title ?? "").padEnd(16)} ${s.status}${s.default ? " *" : ""}`
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
})
|
|
928
|
+
);
|
|
929
|
+
session.command("show <id>").action(
|
|
930
|
+
run(async (id) => {
|
|
931
|
+
const { session: s } = await api(
|
|
932
|
+
"GET",
|
|
933
|
+
`/api/v1/sessions/${encodeURIComponent(id)}`
|
|
934
|
+
);
|
|
935
|
+
console.log(`${s.id}${s.default ? " [default]" : ""}`);
|
|
936
|
+
console.log(` agent ${s.agent ?? "-"}`);
|
|
937
|
+
console.log(` title ${s.title ?? "-"}`);
|
|
938
|
+
console.log(` status ${s.status}`);
|
|
939
|
+
console.log(` model ${s.agentType} \xB7 ${s.llm}`);
|
|
940
|
+
})
|
|
941
|
+
);
|
|
942
|
+
session.command("destroy <id>").description("end the session and tear down its pod (admin scope)").action(
|
|
943
|
+
run(async (id) => {
|
|
944
|
+
await api("DELETE", `/api/v1/sessions/${encodeURIComponent(id)}`);
|
|
945
|
+
console.log(`Destroyed ${id}`);
|
|
946
|
+
})
|
|
947
|
+
);
|
|
948
|
+
session.command("message <ref> <text>").description("send one message (session id, or agent slug = its default session)").option("--detach", "don't follow the stream; exit after the 202").action(
|
|
949
|
+
run(
|
|
950
|
+
async (ref, text, opts) => sendAndFollow(await resolveSessionRef(ref), text, Boolean(opts.detach))
|
|
951
|
+
)
|
|
952
|
+
);
|
|
953
|
+
session.command("chat <ref>").description("interactive REPL over the standing stream").action(run(async (ref) => chatLoop(await resolveSessionRef(ref))));
|
|
954
|
+
session.command("interrupt <ref>").description("abort the in-flight turn").action(
|
|
955
|
+
run(async (ref) => {
|
|
956
|
+
const id = await resolveSessionRef(ref);
|
|
957
|
+
const res = await api(
|
|
958
|
+
"POST",
|
|
959
|
+
`/api/v1/sessions/${encodeURIComponent(id)}/interrupt`
|
|
960
|
+
);
|
|
961
|
+
console.log(res.status === "no_turn" ? "nothing in flight" : "interrupting");
|
|
962
|
+
})
|
|
963
|
+
);
|
|
964
|
+
session.command("logs <ref>").option("-f, --follow", "follow (SSE)").option("--since <duration>", "how far back, e.g. 1h, 30m", "1h").action(
|
|
965
|
+
run(async (ref, opts) => {
|
|
966
|
+
const id = await resolveSessionRef(ref);
|
|
705
967
|
const qs = `?since=${encodeURIComponent(opts.since)}${opts.follow ? "&follow=true" : ""}`;
|
|
706
968
|
if (!opts.follow) {
|
|
707
969
|
const { lines } = await api(
|
|
708
970
|
"GET",
|
|
709
|
-
`/api/v1/
|
|
971
|
+
`/api/v1/sessions/${encodeURIComponent(id)}/logs${qs}`
|
|
710
972
|
);
|
|
711
973
|
for (const entry of lines) console.log(`${entry.at} ${entry.line}`);
|
|
712
974
|
return;
|
|
713
975
|
}
|
|
714
|
-
const { parseSseStream } = await import("./src-
|
|
976
|
+
const { parseSseStream } = await import("./src-Y2XOFL3Z.js");
|
|
715
977
|
const { apiBase: apiBase2 } = await import("./config-HRDRNTUU.js");
|
|
716
978
|
const token = apiToken();
|
|
717
|
-
const res = await fetch(`${apiBase2()}/api/v1/
|
|
718
|
-
headers: {
|
|
979
|
+
const res = await fetch(`${apiBase2()}/api/v1/sessions/${encodeURIComponent(id)}/logs${qs}`, {
|
|
980
|
+
headers: {
|
|
981
|
+
"user-agent": USER_AGENT,
|
|
982
|
+
authorization: `Bearer ${token}`,
|
|
983
|
+
accept: "text/event-stream"
|
|
984
|
+
}
|
|
719
985
|
});
|
|
720
986
|
if (!res.ok || !res.body) throw new ApiError(res.status, "logs_failed", await res.text());
|
|
721
987
|
for await (const frame of parseSseStream(res.body)) {
|
|
@@ -727,12 +993,12 @@ agent.command("logs <slug>").option("-f, --follow", "follow (SSE)").option("--si
|
|
|
727
993
|
}
|
|
728
994
|
})
|
|
729
995
|
);
|
|
730
|
-
async function sendAndFollow(
|
|
996
|
+
async function sendAndFollow(sessionId, text, detach) {
|
|
731
997
|
const controller = new AbortController();
|
|
732
998
|
let opened = null;
|
|
733
999
|
if (!detach) {
|
|
734
1000
|
opened = (async () => {
|
|
735
|
-
for await (const frame of streamEvents(
|
|
1001
|
+
for await (const frame of streamEvents(sessionId, controller.signal)) {
|
|
736
1002
|
renderEvent(frame.event, frame.data);
|
|
737
1003
|
if (frame.event === "turn.status_idle" || frame.event === "turn.interrupted") {
|
|
738
1004
|
controller.abort();
|
|
@@ -742,68 +1008,50 @@ async function sendAndFollow(slug, text, detach) {
|
|
|
742
1008
|
})();
|
|
743
1009
|
await new Promise((r) => setTimeout(r, 300));
|
|
744
1010
|
}
|
|
745
|
-
|
|
746
|
-
"
|
|
747
|
-
|
|
748
|
-
{ parts: [{ type: "text", index: 0, text }] }
|
|
749
|
-
);
|
|
1011
|
+
await api("POST", `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`, {
|
|
1012
|
+
parts: [{ type: "text", index: 0, text }]
|
|
1013
|
+
});
|
|
750
1014
|
if (detach) {
|
|
751
|
-
console.log(
|
|
1015
|
+
console.log("accepted");
|
|
752
1016
|
return;
|
|
753
1017
|
}
|
|
754
1018
|
await opened;
|
|
755
1019
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
)
|
|
760
|
-
)
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
const rl = createInterface2({ input: process.stdin, output: process.stdout, prompt: "> " });
|
|
766
|
-
void (async () => {
|
|
767
|
-
try {
|
|
768
|
-
for await (const frame of streamEvents(slug, controller.signal)) {
|
|
769
|
-
renderEvent(frame.event, frame.data);
|
|
770
|
-
if (frame.event === "turn.status_idle") rl.prompt();
|
|
771
|
-
}
|
|
772
|
-
} catch (error) {
|
|
773
|
-
fail(error);
|
|
774
|
-
}
|
|
775
|
-
})();
|
|
776
|
-
rl.prompt();
|
|
777
|
-
rl.on("line", (line) => {
|
|
778
|
-
const text = line.trim();
|
|
779
|
-
if (!text) {
|
|
780
|
-
rl.prompt();
|
|
781
|
-
return;
|
|
1020
|
+
async function chatLoop(sessionId) {
|
|
1021
|
+
console.log(`Chatting with ${sessionId} \u2014 Ctrl-C to leave.`);
|
|
1022
|
+
const controller = new AbortController();
|
|
1023
|
+
const rl = createInterface3({ input: process.stdin, output: process.stdout, prompt: "> " });
|
|
1024
|
+
void (async () => {
|
|
1025
|
+
try {
|
|
1026
|
+
for await (const frame of streamEvents(sessionId, controller.signal)) {
|
|
1027
|
+
renderEvent(frame.event, frame.data);
|
|
1028
|
+
if (frame.event === "turn.status_idle") rl.prompt();
|
|
782
1029
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
}
|
|
794
|
-
|
|
1030
|
+
} catch (error) {
|
|
1031
|
+
fail(error);
|
|
1032
|
+
}
|
|
1033
|
+
})();
|
|
1034
|
+
rl.prompt();
|
|
1035
|
+
rl.on("line", (line) => {
|
|
1036
|
+
const text = line.trim();
|
|
1037
|
+
if (!text) {
|
|
1038
|
+
rl.prompt();
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
void api("POST", `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`, {
|
|
1042
|
+
parts: [{ type: "text", index: 0, text }]
|
|
1043
|
+
}).catch((error) => {
|
|
1044
|
+
console.error(`sky: ${error instanceof Error ? error.message : String(error)}`);
|
|
1045
|
+
rl.prompt();
|
|
795
1046
|
});
|
|
796
|
-
})
|
|
797
|
-
)
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
console.log(res.status === "no_turn" ? "nothing in flight" : `interrupting ${res.turnId}`);
|
|
805
|
-
})
|
|
806
|
-
);
|
|
1047
|
+
});
|
|
1048
|
+
rl.on("close", () => {
|
|
1049
|
+
controller.abort();
|
|
1050
|
+
process.exit(0);
|
|
1051
|
+
});
|
|
1052
|
+
await new Promise(() => {
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
807
1055
|
var secrets = program.command("secrets").description("agent secrets (values write-only)");
|
|
808
1056
|
secrets.command("set <slug> <pairs...>").description("set KEY=VALUE pairs on the agent").action(
|
|
809
1057
|
run(async (slug, pairs) => {
|
|
@@ -839,7 +1087,7 @@ secrets.command("unset <slug> <key>").action(
|
|
|
839
1087
|
program.command("launch").description("scaffold ./agent.toml if absent, create the agent, print its address").option("-f, --file <path>", "agent file", "agent.toml").action(
|
|
840
1088
|
run(async (opts) => {
|
|
841
1089
|
const path = resolve3(opts.file);
|
|
842
|
-
if (!
|
|
1090
|
+
if (!existsSync4(path)) {
|
|
843
1091
|
const name = basename2(process.cwd()).replace(/[^a-zA-Z0-9 _-]/g, "") || "my-agent";
|
|
844
1092
|
scaffoldAgentFile(path, name);
|
|
845
1093
|
console.log(`Scaffolded ${opts.file} \u2014 edit it anytime; re-apply with \`sky deploy\`.`);
|
|
@@ -849,7 +1097,13 @@ program.command("launch").description("scaffold ./agent.toml if absent, create t
|
|
|
849
1097
|
console.log(`${file.slug} already launched \u2014 use \`sky deploy\` to re-apply.`);
|
|
850
1098
|
return;
|
|
851
1099
|
}
|
|
852
|
-
const {
|
|
1100
|
+
const { vcpus, memoryMb, ...specBody } = spec;
|
|
1101
|
+
const { agent: created } = await api("POST", "/api/v1/agents", specBody);
|
|
1102
|
+
await api("POST", "/api/v1/sessions", {
|
|
1103
|
+
agent: created.slug,
|
|
1104
|
+
...vcpus !== void 0 ? { vcpus } : {},
|
|
1105
|
+
...memoryMb !== void 0 ? { memoryMb } : {}
|
|
1106
|
+
});
|
|
853
1107
|
stampSlug(path, created.slug);
|
|
854
1108
|
console.log(`Launched ${created.slug} (${created.agentType} \xB7 ${created.llm})`);
|
|
855
1109
|
console.log(` sky agent message ${created.slug} "hello"`);
|
|
@@ -862,7 +1116,13 @@ program.command("deploy").description("re-apply ./agent.toml to the existing age
|
|
|
862
1116
|
const { file, spec } = readAgentFile(path);
|
|
863
1117
|
if (!file.slug) {
|
|
864
1118
|
console.log("No slug in the file yet \u2014 running launch instead.");
|
|
865
|
-
const {
|
|
1119
|
+
const { vcpus, memoryMb, ...specBody } = spec;
|
|
1120
|
+
const { agent: created } = await api("POST", "/api/v1/agents", specBody);
|
|
1121
|
+
await api("POST", "/api/v1/sessions", {
|
|
1122
|
+
agent: created.slug,
|
|
1123
|
+
...vcpus !== void 0 ? { vcpus } : {},
|
|
1124
|
+
...memoryMb !== void 0 ? { memoryMb } : {}
|
|
1125
|
+
});
|
|
866
1126
|
stampSlug(path, created.slug);
|
|
867
1127
|
console.log(`Launched ${created.slug}`);
|
|
868
1128
|
return;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
external_exports,
|
|
3
|
-
messagePartSchema
|
|
4
|
-
|
|
5
|
-
} from "./chunk-DTVZOF77.js";
|
|
3
|
+
messagePartSchema
|
|
4
|
+
} from "./chunk-L5LLCKZW.js";
|
|
6
5
|
import "./chunk-MLKGABMK.js";
|
|
7
6
|
|
|
8
7
|
// ../../packages/chat/src/stream.ts
|
|
@@ -117,25 +116,16 @@ async function postTurn(baseUrl, body, options = {}) {
|
|
|
117
116
|
throw new Error(`pod unreachable${suffix}`);
|
|
118
117
|
}
|
|
119
118
|
if (!res.ok) throw new Error(`pod message failed ${res.status}: ${await res.text()}`);
|
|
120
|
-
const data = await res.json();
|
|
121
|
-
return data.messages ?? [];
|
|
122
119
|
}
|
|
123
120
|
async function sendAgentTurn(baseUrl, parts, options = {}) {
|
|
124
|
-
|
|
125
|
-
return messages.flatMap((m) => m.parts ?? []).map((part, index) => ({ ...part, index }));
|
|
126
|
-
}
|
|
127
|
-
async function sendAgentMessage(baseUrl, text, options = {}) {
|
|
128
|
-
return textFromParts(await sendAgentTurn(baseUrl, textParts(text), options));
|
|
121
|
+
await postTurn(baseUrl, { parts }, options);
|
|
129
122
|
}
|
|
130
123
|
function textFromParts(parts) {
|
|
131
124
|
return parts.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join(" ").trim();
|
|
132
125
|
}
|
|
133
|
-
function replyParts(reply) {
|
|
134
|
-
return textParts(reply || "(no reply)");
|
|
135
|
-
}
|
|
136
126
|
async function postChatProxy(args) {
|
|
137
127
|
const url = new URL(
|
|
138
|
-
`/api/v1/
|
|
128
|
+
`/api/v1/sessions/${encodeURIComponent(args.agentRouteId)}/messages`,
|
|
139
129
|
normalizeBaseUrl(args.baseUrl)
|
|
140
130
|
);
|
|
141
131
|
const headers = {
|
|
@@ -179,8 +169,6 @@ export {
|
|
|
179
169
|
chatProxyRequestSchema,
|
|
180
170
|
parseSseStream,
|
|
181
171
|
postChatProxy,
|
|
182
|
-
replyParts,
|
|
183
|
-
sendAgentMessage,
|
|
184
172
|
sendAgentTurn,
|
|
185
173
|
streamAgentEvents,
|
|
186
174
|
textFromParts
|