@agentsky/sky 0.1.0 → 0.2.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/dist/index.js +168 -78
- package/dist/{src-KNBIGOZP.js → src-CNT7GXZH.js} +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -70,10 +70,28 @@ async function api(method, path, body, opts = {}) {
|
|
|
70
70
|
if (!res.ok) await parseError(res);
|
|
71
71
|
return await res.json();
|
|
72
72
|
}
|
|
73
|
-
async function
|
|
74
|
-
|
|
73
|
+
async function resolveSessionRef(ref) {
|
|
74
|
+
if (ref.startsWith("sess-")) return ref;
|
|
75
|
+
const { agent: agent2 } = await api(
|
|
76
|
+
"GET",
|
|
77
|
+
`/api/v1/agents/${encodeURIComponent(ref)}`
|
|
78
|
+
).catch(async () => {
|
|
79
|
+
await api("GET", `/api/v1/sessions/${encodeURIComponent(ref)}`);
|
|
80
|
+
return { agent: { slug: ref, defaultSessionId: ref } };
|
|
81
|
+
});
|
|
82
|
+
if (!agent2.defaultSessionId) {
|
|
83
|
+
throw new ApiError(
|
|
84
|
+
404,
|
|
85
|
+
"no_sessions",
|
|
86
|
+
`agent ${agent2.slug} has no sessions \u2014 create one: sky session create ${agent2.slug}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return agent2.defaultSessionId;
|
|
90
|
+
}
|
|
91
|
+
async function* streamEvents(sessionId, signal) {
|
|
92
|
+
const { parseSseStream } = await import("./src-CNT7GXZH.js");
|
|
75
93
|
const res = await fetch(
|
|
76
|
-
`${apiBase()}/api/v1/
|
|
94
|
+
`${apiBase()}/api/v1/sessions/${encodeURIComponent(sessionId)}/stream`,
|
|
77
95
|
{
|
|
78
96
|
headers: { ...authHeaders(), accept: "text/event-stream" },
|
|
79
97
|
signal
|
|
@@ -362,6 +380,7 @@ async function createClone(local, opts) {
|
|
|
362
380
|
throw error;
|
|
363
381
|
}
|
|
364
382
|
}
|
|
383
|
+
await api("POST", "/api/v1/sessions", { agent: created.slug });
|
|
365
384
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
366
385
|
writeLink(local.configRoot, {
|
|
367
386
|
baseUrl: apiBase(),
|
|
@@ -593,7 +612,7 @@ function renderEvent(event, data) {
|
|
|
593
612
|
|
|
594
613
|
// src/index.ts
|
|
595
614
|
var program = new Command();
|
|
596
|
-
program.name("sky").description("Launch and talk to long-lived agents \u2014 agentsky.dev").version("0.
|
|
615
|
+
program.name("sky").description("Launch and talk to long-lived agents \u2014 agentsky.dev").version("0.2.0");
|
|
597
616
|
function fail(error) {
|
|
598
617
|
if (error instanceof ApiError) console.error(`sky: ${error.message} (${error.code})`);
|
|
599
618
|
else console.error(`sky: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -653,8 +672,8 @@ universe.command("show").action(
|
|
|
653
672
|
}
|
|
654
673
|
})
|
|
655
674
|
);
|
|
656
|
-
var agent = program.command("agent").description("create, inspect, talk
|
|
657
|
-
agent.command("create").description("create an agent
|
|
675
|
+
var agent = program.command("agent").description("agent specs: create, inspect, talk (via the default session)");
|
|
676
|
+
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
677
|
run(async (opts) => {
|
|
659
678
|
const spec = opts.file ? readAgentFile(opts.file).spec : {
|
|
660
679
|
name: opts.name ?? "My agent",
|
|
@@ -662,11 +681,9 @@ agent.command("create").description("create an agent (flags-only; bare create =
|
|
|
662
681
|
llm: opts.llm,
|
|
663
682
|
displayName: opts.name
|
|
664
683
|
};
|
|
665
|
-
if (opts.vcpus !== void 0) spec.vcpus = Number(opts.vcpus);
|
|
666
|
-
if (opts.memory !== void 0) spec.memoryMb = Number(opts.memory);
|
|
667
684
|
const { agent: created } = await api("POST", "/api/v1/agents", spec);
|
|
668
|
-
console.log(`Created ${created.slug} (${created.agentType} \xB7 ${created.llm})
|
|
669
|
-
console.log(`
|
|
685
|
+
console.log(`Created ${created.slug} (${created.agentType} \xB7 ${created.llm}) \u2014 spec only.`);
|
|
686
|
+
console.log(`Start it: sky session create ${created.slug}`);
|
|
670
687
|
})
|
|
671
688
|
);
|
|
672
689
|
agent.command("list").action(
|
|
@@ -677,8 +694,9 @@ agent.command("list").action(
|
|
|
677
694
|
return;
|
|
678
695
|
}
|
|
679
696
|
for (const a of agents) {
|
|
697
|
+
const state = a.archived ? "archived" : `${a.sessionCount} session${a.sessionCount === 1 ? "" : "s"}`;
|
|
680
698
|
console.log(
|
|
681
|
-
`${a.slug.padEnd(24)} ${a.displayName.padEnd(20)} ${a.agentType}/${a.llm} ${
|
|
699
|
+
`${a.slug.padEnd(24)} ${a.displayName.padEnd(20)} ${a.agentType}/${a.llm} ${state}`
|
|
682
700
|
);
|
|
683
701
|
}
|
|
684
702
|
})
|
|
@@ -686,35 +704,113 @@ agent.command("list").action(
|
|
|
686
704
|
agent.command("show <slug>").action(
|
|
687
705
|
run(async (slug) => {
|
|
688
706
|
const { agent: a } = await api("GET", `/api/v1/agents/${encodeURIComponent(slug)}`);
|
|
689
|
-
console.log(`${a.slug} \u2014 ${a.displayName}`);
|
|
707
|
+
console.log(`${a.slug} \u2014 ${a.displayName}${a.archived ? " (archived)" : ""}`);
|
|
690
708
|
console.log(` type ${a.agentType} \xB7 ${a.llm}`);
|
|
691
|
-
console.log(`
|
|
709
|
+
console.log(` version ${a.version}`);
|
|
710
|
+
console.log(` sessions ${a.sessionCount}`);
|
|
692
711
|
console.log(` universe ${a.universe}`);
|
|
693
712
|
if (a.capabilities.length) console.log(` caps ${a.capabilities.join(", ")}`);
|
|
694
713
|
if (a.prompt) console.log(` prompt ${a.prompt.split("\n")[0]?.slice(0, 80)}\u2026`);
|
|
695
714
|
})
|
|
696
715
|
);
|
|
697
|
-
agent.command("
|
|
716
|
+
agent.command("archive <slug>").description("retire the spec \u2014 read-only, running sessions unaffected (admin scope)").action(
|
|
717
|
+
run(async (slug) => {
|
|
718
|
+
await api("POST", `/api/v1/agents/${encodeURIComponent(slug)}/archive`);
|
|
719
|
+
console.log(`Archived ${slug} \u2014 sessions keep running; new sessions are rejected.`);
|
|
720
|
+
})
|
|
721
|
+
);
|
|
722
|
+
agent.command("destroy <slug>").description("delete the spec; requires all sessions destroyed first (admin scope)").action(
|
|
698
723
|
run(async (slug) => {
|
|
699
724
|
await api("DELETE", `/api/v1/agents/${encodeURIComponent(slug)}`);
|
|
700
725
|
console.log(`Destroyed ${slug}`);
|
|
701
726
|
})
|
|
702
727
|
);
|
|
703
|
-
agent.command("
|
|
704
|
-
run(
|
|
728
|
+
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(
|
|
729
|
+
run(
|
|
730
|
+
async (slug, text, opts) => sendAndFollow(await resolveSessionRef(slug), text, Boolean(opts.detach))
|
|
731
|
+
)
|
|
732
|
+
);
|
|
733
|
+
agent.command("chat <slug>").description("interactive REPL with the default session").action(run(async (slug) => chatLoop(await resolveSessionRef(slug))));
|
|
734
|
+
var session = program.command("session").description("sessions: the running instances of an agent");
|
|
735
|
+
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(
|
|
736
|
+
run(async (agentRef, opts) => {
|
|
737
|
+
const { session: created } = await api("POST", "/api/v1/sessions", {
|
|
738
|
+
agent: agentRef,
|
|
739
|
+
...opts.title ? { title: opts.title } : {},
|
|
740
|
+
...opts.vcpus !== void 0 ? { vcpus: Number(opts.vcpus) } : {},
|
|
741
|
+
...opts.memory !== void 0 ? { memoryMb: Number(opts.memory) } : {},
|
|
742
|
+
...opts.message ? { initial_events: [{ type: "user.message", parts: [{ type: "text", index: 0, text: opts.message }] }] } : {}
|
|
743
|
+
});
|
|
744
|
+
console.log(`Created ${created.id} (${created.agent} \xB7 ${created.status})${created.default ? " [default]" : ""}`);
|
|
745
|
+
console.log(` sky agent message ${created.agent} "hello"`);
|
|
746
|
+
})
|
|
747
|
+
);
|
|
748
|
+
session.command("list [agent]").action(
|
|
749
|
+
run(async (agentRef) => {
|
|
750
|
+
const qs = agentRef ? `?agent=${encodeURIComponent(agentRef)}` : "";
|
|
751
|
+
const { sessions } = await api("GET", `/api/v1/sessions${qs}`);
|
|
752
|
+
if (!sessions.length) {
|
|
753
|
+
console.log("No sessions. `sky session create <agent>` to start one.");
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
for (const s of sessions) {
|
|
757
|
+
console.log(
|
|
758
|
+
`${s.id.padEnd(24)} ${(s.agent ?? "-").padEnd(20)} ${(s.title ?? "").padEnd(16)} ${s.status}${s.default ? " *" : ""}`
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
})
|
|
762
|
+
);
|
|
763
|
+
session.command("show <id>").action(
|
|
764
|
+
run(async (id) => {
|
|
765
|
+
const { session: s } = await api(
|
|
766
|
+
"GET",
|
|
767
|
+
`/api/v1/sessions/${encodeURIComponent(id)}`
|
|
768
|
+
);
|
|
769
|
+
console.log(`${s.id}${s.default ? " [default]" : ""}`);
|
|
770
|
+
console.log(` agent ${s.agent ?? "-"}`);
|
|
771
|
+
console.log(` title ${s.title ?? "-"}`);
|
|
772
|
+
console.log(` status ${s.status}`);
|
|
773
|
+
console.log(` model ${s.agentType} \xB7 ${s.llm}`);
|
|
774
|
+
})
|
|
775
|
+
);
|
|
776
|
+
session.command("destroy <id>").description("end the session and tear down its pod (admin scope)").action(
|
|
777
|
+
run(async (id) => {
|
|
778
|
+
await api("DELETE", `/api/v1/sessions/${encodeURIComponent(id)}`);
|
|
779
|
+
console.log(`Destroyed ${id}`);
|
|
780
|
+
})
|
|
781
|
+
);
|
|
782
|
+
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(
|
|
783
|
+
run(
|
|
784
|
+
async (ref, text, opts) => sendAndFollow(await resolveSessionRef(ref), text, Boolean(opts.detach))
|
|
785
|
+
)
|
|
786
|
+
);
|
|
787
|
+
session.command("chat <ref>").description("interactive REPL over the standing stream").action(run(async (ref) => chatLoop(await resolveSessionRef(ref))));
|
|
788
|
+
session.command("interrupt <ref>").description("abort the in-flight turn").action(
|
|
789
|
+
run(async (ref) => {
|
|
790
|
+
const id = await resolveSessionRef(ref);
|
|
791
|
+
const res = await api(
|
|
792
|
+
"POST",
|
|
793
|
+
`/api/v1/sessions/${encodeURIComponent(id)}/interrupt`
|
|
794
|
+
);
|
|
795
|
+
console.log(res.status === "no_turn" ? "nothing in flight" : "interrupting");
|
|
796
|
+
})
|
|
797
|
+
);
|
|
798
|
+
session.command("logs <ref>").option("-f, --follow", "follow (SSE)").option("--since <duration>", "how far back, e.g. 1h, 30m", "1h").action(
|
|
799
|
+
run(async (ref, opts) => {
|
|
800
|
+
const id = await resolveSessionRef(ref);
|
|
705
801
|
const qs = `?since=${encodeURIComponent(opts.since)}${opts.follow ? "&follow=true" : ""}`;
|
|
706
802
|
if (!opts.follow) {
|
|
707
803
|
const { lines } = await api(
|
|
708
804
|
"GET",
|
|
709
|
-
`/api/v1/
|
|
805
|
+
`/api/v1/sessions/${encodeURIComponent(id)}/logs${qs}`
|
|
710
806
|
);
|
|
711
807
|
for (const entry of lines) console.log(`${entry.at} ${entry.line}`);
|
|
712
808
|
return;
|
|
713
809
|
}
|
|
714
|
-
const { parseSseStream } = await import("./src-
|
|
810
|
+
const { parseSseStream } = await import("./src-CNT7GXZH.js");
|
|
715
811
|
const { apiBase: apiBase2 } = await import("./config-HRDRNTUU.js");
|
|
716
812
|
const token = apiToken();
|
|
717
|
-
const res = await fetch(`${apiBase2()}/api/v1/
|
|
813
|
+
const res = await fetch(`${apiBase2()}/api/v1/sessions/${encodeURIComponent(id)}/logs${qs}`, {
|
|
718
814
|
headers: { authorization: `Bearer ${token}`, accept: "text/event-stream" }
|
|
719
815
|
});
|
|
720
816
|
if (!res.ok || !res.body) throw new ApiError(res.status, "logs_failed", await res.text());
|
|
@@ -727,12 +823,12 @@ agent.command("logs <slug>").option("-f, --follow", "follow (SSE)").option("--si
|
|
|
727
823
|
}
|
|
728
824
|
})
|
|
729
825
|
);
|
|
730
|
-
async function sendAndFollow(
|
|
826
|
+
async function sendAndFollow(sessionId, text, detach) {
|
|
731
827
|
const controller = new AbortController();
|
|
732
828
|
let opened = null;
|
|
733
829
|
if (!detach) {
|
|
734
830
|
opened = (async () => {
|
|
735
|
-
for await (const frame of streamEvents(
|
|
831
|
+
for await (const frame of streamEvents(sessionId, controller.signal)) {
|
|
736
832
|
renderEvent(frame.event, frame.data);
|
|
737
833
|
if (frame.event === "turn.status_idle" || frame.event === "turn.interrupted") {
|
|
738
834
|
controller.abort();
|
|
@@ -742,68 +838,50 @@ async function sendAndFollow(slug, text, detach) {
|
|
|
742
838
|
})();
|
|
743
839
|
await new Promise((r) => setTimeout(r, 300));
|
|
744
840
|
}
|
|
745
|
-
|
|
746
|
-
"
|
|
747
|
-
|
|
748
|
-
{ parts: [{ type: "text", index: 0, text }] }
|
|
749
|
-
);
|
|
841
|
+
await api("POST", `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`, {
|
|
842
|
+
parts: [{ type: "text", index: 0, text }]
|
|
843
|
+
});
|
|
750
844
|
if (detach) {
|
|
751
|
-
console.log(
|
|
845
|
+
console.log("accepted");
|
|
752
846
|
return;
|
|
753
847
|
}
|
|
754
848
|
await opened;
|
|
755
849
|
}
|
|
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;
|
|
850
|
+
async function chatLoop(sessionId) {
|
|
851
|
+
console.log(`Chatting with ${sessionId} \u2014 Ctrl-C to leave.`);
|
|
852
|
+
const controller = new AbortController();
|
|
853
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout, prompt: "> " });
|
|
854
|
+
void (async () => {
|
|
855
|
+
try {
|
|
856
|
+
for await (const frame of streamEvents(sessionId, controller.signal)) {
|
|
857
|
+
renderEvent(frame.event, frame.data);
|
|
858
|
+
if (frame.event === "turn.status_idle") rl.prompt();
|
|
782
859
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
}
|
|
794
|
-
|
|
860
|
+
} catch (error) {
|
|
861
|
+
fail(error);
|
|
862
|
+
}
|
|
863
|
+
})();
|
|
864
|
+
rl.prompt();
|
|
865
|
+
rl.on("line", (line) => {
|
|
866
|
+
const text = line.trim();
|
|
867
|
+
if (!text) {
|
|
868
|
+
rl.prompt();
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
void api("POST", `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`, {
|
|
872
|
+
parts: [{ type: "text", index: 0, text }]
|
|
873
|
+
}).catch((error) => {
|
|
874
|
+
console.error(`sky: ${error instanceof Error ? error.message : String(error)}`);
|
|
875
|
+
rl.prompt();
|
|
795
876
|
});
|
|
796
|
-
})
|
|
797
|
-
)
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
console.log(res.status === "no_turn" ? "nothing in flight" : `interrupting ${res.turnId}`);
|
|
805
|
-
})
|
|
806
|
-
);
|
|
877
|
+
});
|
|
878
|
+
rl.on("close", () => {
|
|
879
|
+
controller.abort();
|
|
880
|
+
process.exit(0);
|
|
881
|
+
});
|
|
882
|
+
await new Promise(() => {
|
|
883
|
+
});
|
|
884
|
+
}
|
|
807
885
|
var secrets = program.command("secrets").description("agent secrets (values write-only)");
|
|
808
886
|
secrets.command("set <slug> <pairs...>").description("set KEY=VALUE pairs on the agent").action(
|
|
809
887
|
run(async (slug, pairs) => {
|
|
@@ -849,7 +927,13 @@ program.command("launch").description("scaffold ./agent.toml if absent, create t
|
|
|
849
927
|
console.log(`${file.slug} already launched \u2014 use \`sky deploy\` to re-apply.`);
|
|
850
928
|
return;
|
|
851
929
|
}
|
|
852
|
-
const {
|
|
930
|
+
const { vcpus, memoryMb, ...specBody } = spec;
|
|
931
|
+
const { agent: created } = await api("POST", "/api/v1/agents", specBody);
|
|
932
|
+
await api("POST", "/api/v1/sessions", {
|
|
933
|
+
agent: created.slug,
|
|
934
|
+
...vcpus !== void 0 ? { vcpus } : {},
|
|
935
|
+
...memoryMb !== void 0 ? { memoryMb } : {}
|
|
936
|
+
});
|
|
853
937
|
stampSlug(path, created.slug);
|
|
854
938
|
console.log(`Launched ${created.slug} (${created.agentType} \xB7 ${created.llm})`);
|
|
855
939
|
console.log(` sky agent message ${created.slug} "hello"`);
|
|
@@ -862,7 +946,13 @@ program.command("deploy").description("re-apply ./agent.toml to the existing age
|
|
|
862
946
|
const { file, spec } = readAgentFile(path);
|
|
863
947
|
if (!file.slug) {
|
|
864
948
|
console.log("No slug in the file yet \u2014 running launch instead.");
|
|
865
|
-
const {
|
|
949
|
+
const { vcpus, memoryMb, ...specBody } = spec;
|
|
950
|
+
const { agent: created } = await api("POST", "/api/v1/agents", specBody);
|
|
951
|
+
await api("POST", "/api/v1/sessions", {
|
|
952
|
+
agent: created.slug,
|
|
953
|
+
...vcpus !== void 0 ? { vcpus } : {},
|
|
954
|
+
...memoryMb !== void 0 ? { memoryMb } : {}
|
|
955
|
+
});
|
|
866
956
|
stampSlug(path, created.slug);
|
|
867
957
|
console.log(`Launched ${created.slug}`);
|
|
868
958
|
return;
|
|
@@ -135,7 +135,7 @@ function replyParts(reply) {
|
|
|
135
135
|
}
|
|
136
136
|
async function postChatProxy(args) {
|
|
137
137
|
const url = new URL(
|
|
138
|
-
`/api/v1/
|
|
138
|
+
`/api/v1/sessions/${encodeURIComponent(args.agentRouteId)}/messages`,
|
|
139
139
|
normalizeBaseUrl(args.baseUrl)
|
|
140
140
|
);
|
|
141
141
|
const headers = {
|