@deepstrike/sdk 0.1.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/README.md +296 -0
- package/dist/agent.d.ts +62 -0
- package/dist/agent.js +321 -0
- package/dist/harness/harness.d.ts +40 -0
- package/dist/harness/harness.js +100 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +12 -0
- package/dist/knowledge/source.d.ts +3 -0
- package/dist/knowledge/source.js +1 -0
- package/dist/memory/protocols.d.ts +48 -0
- package/dist/memory/protocols.js +2 -0
- package/dist/memory/working.d.ts +8 -0
- package/dist/memory/working.js +8 -0
- package/dist/providers/anthropic.d.ts +15 -0
- package/dist/providers/anthropic.js +102 -0
- package/dist/providers/base.d.ts +15 -0
- package/dist/providers/base.js +46 -0
- package/dist/providers/ollama.d.ts +9 -0
- package/dist/providers/ollama.js +58 -0
- package/dist/providers/openai.d.ts +44 -0
- package/dist/providers/openai.js +144 -0
- package/dist/safety/permissions.d.ts +17 -0
- package/dist/safety/permissions.js +32 -0
- package/dist/signals/gateway.d.ts +30 -0
- package/dist/signals/gateway.js +71 -0
- package/dist/signals/scheduled.d.ts +9 -0
- package/dist/signals/scheduled.js +18 -0
- package/dist/signals/types.d.ts +8 -0
- package/dist/signals/types.js +1 -0
- package/dist/skills/loader.d.ts +11 -0
- package/dist/skills/loader.js +43 -0
- package/dist/tools/index.d.ts +12 -0
- package/dist/tools/index.js +25 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.js +1 -0
- package/package.json +25 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
import { CircuitBreaker, normalizeToolCall } from "./base.js";
|
|
3
|
+
export class OpenAIProvider {
|
|
4
|
+
model;
|
|
5
|
+
client;
|
|
6
|
+
circuit;
|
|
7
|
+
maxRetries;
|
|
8
|
+
baseDelay;
|
|
9
|
+
constructor(apiKey, model = "gpt-4o", retry = { maxRetries: 3, baseDelay: 1000 }, baseURL = "https://api.openai.com/v1") {
|
|
10
|
+
this.model = model;
|
|
11
|
+
this.client = new OpenAI({ apiKey, baseURL });
|
|
12
|
+
this.circuit = new CircuitBreaker();
|
|
13
|
+
this.maxRetries = retry.maxRetries;
|
|
14
|
+
this.baseDelay = retry.baseDelay;
|
|
15
|
+
}
|
|
16
|
+
buildTools(tools) {
|
|
17
|
+
return tools.map(t => ({
|
|
18
|
+
type: "function",
|
|
19
|
+
function: { name: t.name, description: t.description, parameters: JSON.parse(t.parameters) },
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
async complete(messages, tools) {
|
|
23
|
+
if (this.circuit.isOpen())
|
|
24
|
+
throw new Error("Circuit breaker open");
|
|
25
|
+
const msgs = messages.map(m => ({ role: m.role, content: m.content }));
|
|
26
|
+
let lastErr;
|
|
27
|
+
for (let i = 0; i < this.maxRetries; i++) {
|
|
28
|
+
try {
|
|
29
|
+
const resp = await this.client.chat.completions.create({
|
|
30
|
+
model: this.model,
|
|
31
|
+
messages: msgs,
|
|
32
|
+
...(tools.length ? { tools: this.buildTools(tools) } : {}),
|
|
33
|
+
});
|
|
34
|
+
this.circuit.recordSuccess();
|
|
35
|
+
const choice = resp.choices[0].message;
|
|
36
|
+
const toolCalls = (choice.tool_calls ?? []).map(tc => normalizeToolCall(tc.id, tc.function.name, tc.function.arguments)).filter(Boolean);
|
|
37
|
+
return { role: "assistant", content: choice.content ?? "", tokenCount: resp.usage?.total_tokens, toolCalls };
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
lastErr = err;
|
|
41
|
+
this.circuit.recordFailure();
|
|
42
|
+
if (i < this.maxRetries - 1)
|
|
43
|
+
await new Promise(r => setTimeout(r, this.baseDelay * 2 ** i));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
throw lastErr;
|
|
47
|
+
}
|
|
48
|
+
async *stream(messages, tools, extensions) {
|
|
49
|
+
const msgs = messages.map(m => ({ role: m.role, content: m.content }));
|
|
50
|
+
const toolCallBufs = {};
|
|
51
|
+
const stream = await this.client.chat.completions.create({
|
|
52
|
+
model: this.model,
|
|
53
|
+
messages: msgs,
|
|
54
|
+
...(tools.length ? { tools: this.buildTools(tools) } : {}),
|
|
55
|
+
stream: true,
|
|
56
|
+
});
|
|
57
|
+
for await (const chunk of stream) {
|
|
58
|
+
const choice = chunk.choices[0];
|
|
59
|
+
if (!choice)
|
|
60
|
+
continue;
|
|
61
|
+
const delta = choice.delta;
|
|
62
|
+
if (delta.content)
|
|
63
|
+
yield { type: "text_delta", delta: delta.content };
|
|
64
|
+
for (const tc of delta.tool_calls ?? []) {
|
|
65
|
+
const idx = tc.index;
|
|
66
|
+
if (!toolCallBufs[idx])
|
|
67
|
+
toolCallBufs[idx] = { id: tc.id ?? "", name: "", argsBuf: "" };
|
|
68
|
+
if (tc.function?.name)
|
|
69
|
+
toolCallBufs[idx].name += tc.function.name;
|
|
70
|
+
toolCallBufs[idx].argsBuf += tc.function?.arguments ?? "";
|
|
71
|
+
}
|
|
72
|
+
if (choice.finish_reason === "tool_calls") {
|
|
73
|
+
for (const tb of Object.values(toolCallBufs)) {
|
|
74
|
+
let args = {};
|
|
75
|
+
try {
|
|
76
|
+
args = JSON.parse(tb.argsBuf || "{}");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
args = {};
|
|
80
|
+
}
|
|
81
|
+
yield { type: "tool_call", id: tb.id, name: tb.name, arguments: args };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const DASHSCOPE_BASE = "https://dashscope.aliyuncs.com/compatible-mode/v1";
|
|
88
|
+
const DEEPSEEK_BASE = "https://api.deepseek.com/v1";
|
|
89
|
+
const MINIMAX_BASE = "https://api.minimax.chat/v1";
|
|
90
|
+
const DEEPSEEK_REASONERS = new Set(["deepseek-reasoner", "deepseek-r1"]);
|
|
91
|
+
const MINIMAX_REASONERS = new Set(["MiniMax-M1", "minimax-m1"]);
|
|
92
|
+
export class QwenProvider extends OpenAIProvider {
|
|
93
|
+
constructor(apiKey, model = "qwen-plus", retry) {
|
|
94
|
+
super(apiKey, model, retry, DASHSCOPE_BASE);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export class DeepSeekProvider extends OpenAIProvider {
|
|
98
|
+
constructor(apiKey, model = "deepseek-chat", retry) {
|
|
99
|
+
super(apiKey, model, retry, DEEPSEEK_BASE);
|
|
100
|
+
}
|
|
101
|
+
async *stream(messages, tools, extensions) {
|
|
102
|
+
const exposeReasoning = extensions?.exposeReasoning ?? false;
|
|
103
|
+
const msgs = messages.map(m => ({ role: m.role, content: m.content }));
|
|
104
|
+
const isReasoner = DEEPSEEK_REASONERS.has(this.model);
|
|
105
|
+
const stream = await this.client.chat.completions.create({
|
|
106
|
+
model: this.model,
|
|
107
|
+
messages: msgs,
|
|
108
|
+
...(!isReasoner && tools.length ? { tools: this.buildTools(tools) } : {}),
|
|
109
|
+
stream: true,
|
|
110
|
+
});
|
|
111
|
+
for await (const chunk of stream) {
|
|
112
|
+
const delta = chunk.choices[0]?.delta;
|
|
113
|
+
if (exposeReasoning && delta.reasoning_content) {
|
|
114
|
+
yield { type: "thinking_delta", delta: delta.reasoning_content };
|
|
115
|
+
}
|
|
116
|
+
if (delta.content)
|
|
117
|
+
yield { type: "text_delta", delta: delta.content };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
export class MiniMaxProvider extends OpenAIProvider {
|
|
122
|
+
constructor(apiKey, model = "MiniMax-Text-01", retry) {
|
|
123
|
+
super(apiKey, model, retry, MINIMAX_BASE);
|
|
124
|
+
}
|
|
125
|
+
async *stream(messages, tools, extensions) {
|
|
126
|
+
const exposeReasoning = extensions?.exposeReasoning ?? false;
|
|
127
|
+
const msgs = messages.map(m => ({ role: m.role, content: m.content }));
|
|
128
|
+
const isReasoner = MINIMAX_REASONERS.has(this.model);
|
|
129
|
+
const stream = await this.client.chat.completions.create({
|
|
130
|
+
model: this.model,
|
|
131
|
+
messages: msgs,
|
|
132
|
+
...(!isReasoner && tools.length ? { tools: this.buildTools(tools) } : {}),
|
|
133
|
+
stream: true,
|
|
134
|
+
});
|
|
135
|
+
for await (const chunk of stream) {
|
|
136
|
+
const delta = chunk.choices[0]?.delta;
|
|
137
|
+
if (exposeReasoning && delta.reasoning_content) {
|
|
138
|
+
yield { type: "thinking_delta", delta: delta.reasoning_content };
|
|
139
|
+
}
|
|
140
|
+
if (delta.content)
|
|
141
|
+
yield { type: "text_delta", delta: delta.content };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare enum PermissionMode {
|
|
2
|
+
DEFAULT = "DEFAULT",
|
|
3
|
+
PLAN = "PLAN",
|
|
4
|
+
AUTO = "AUTO"
|
|
5
|
+
}
|
|
6
|
+
export interface PermissionDecision {
|
|
7
|
+
allowed: boolean;
|
|
8
|
+
reason: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class PermissionManager {
|
|
11
|
+
private mode;
|
|
12
|
+
private grants;
|
|
13
|
+
constructor(mode?: PermissionMode);
|
|
14
|
+
grant(resource: string, action: string): this;
|
|
15
|
+
revoke(resource: string, action: string): this;
|
|
16
|
+
evaluate(resource: string, action: string): PermissionDecision;
|
|
17
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export var PermissionMode;
|
|
2
|
+
(function (PermissionMode) {
|
|
3
|
+
PermissionMode["DEFAULT"] = "DEFAULT";
|
|
4
|
+
PermissionMode["PLAN"] = "PLAN";
|
|
5
|
+
PermissionMode["AUTO"] = "AUTO";
|
|
6
|
+
})(PermissionMode || (PermissionMode = {}));
|
|
7
|
+
export class PermissionManager {
|
|
8
|
+
mode;
|
|
9
|
+
grants = new Map();
|
|
10
|
+
constructor(mode = PermissionMode.DEFAULT) {
|
|
11
|
+
this.mode = mode;
|
|
12
|
+
}
|
|
13
|
+
grant(resource, action) {
|
|
14
|
+
if (!this.grants.has(resource))
|
|
15
|
+
this.grants.set(resource, new Set());
|
|
16
|
+
this.grants.get(resource).add(action);
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
revoke(resource, action) {
|
|
20
|
+
this.grants.get(resource)?.delete(action);
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
evaluate(resource, action) {
|
|
24
|
+
if (this.mode === PermissionMode.AUTO)
|
|
25
|
+
return { allowed: true, reason: "AUTO mode" };
|
|
26
|
+
if (this.mode === PermissionMode.PLAN)
|
|
27
|
+
return { allowed: false, reason: "PLAN mode blocks all" };
|
|
28
|
+
const actions = this.grants.get(resource);
|
|
29
|
+
const allowed = !!(actions && (actions.has(action) || actions.has("*")));
|
|
30
|
+
return { allowed, reason: allowed ? "granted" : "not granted" };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RuntimeSignal } from "./types.js";
|
|
2
|
+
import type { ScheduledPrompt } from "./scheduled.js";
|
|
3
|
+
/**
|
|
4
|
+
* SignalGateway — the entry point for all external signals into the agent.
|
|
5
|
+
*
|
|
6
|
+
* Responsibilities:
|
|
7
|
+
* - Cron scheduling: fires ScheduledPrompts at the right time (deduplicated)
|
|
8
|
+
* - Webhook ingestion: converts raw external payloads to RuntimeSignal
|
|
9
|
+
* - Routes all signals through the kernel SignalRouter for priority + dedup
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* const gateway = new SignalGateway()
|
|
13
|
+
* gateway.schedule(new ScheduledPrompt("summarize", Date.now() + 60_000))
|
|
14
|
+
* gateway.onSignal(sig => agent.ingestSignal(sig))
|
|
15
|
+
*/
|
|
16
|
+
export declare class SignalGateway {
|
|
17
|
+
private timers;
|
|
18
|
+
private listeners;
|
|
19
|
+
private router;
|
|
20
|
+
init(): Promise<void>;
|
|
21
|
+
onSignal(listener: (sig: RuntimeSignal) => void): void;
|
|
22
|
+
/** Schedule a ScheduledPrompt to fire at its runAtMs. Idempotent by goal. */
|
|
23
|
+
schedule(prompt: ScheduledPrompt): void;
|
|
24
|
+
/** Cancel a scheduled prompt. */
|
|
25
|
+
cancel(goal: string, runAtMs: number): void;
|
|
26
|
+
/** Ingest a raw external signal (e.g. from a webhook handler). */
|
|
27
|
+
ingest(sig: RuntimeSignal): void;
|
|
28
|
+
private emit;
|
|
29
|
+
destroy(): void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2
|
+
async function loadKernel() {
|
|
3
|
+
return import("@deepstrike/core");
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* SignalGateway — the entry point for all external signals into the agent.
|
|
7
|
+
*
|
|
8
|
+
* Responsibilities:
|
|
9
|
+
* - Cron scheduling: fires ScheduledPrompts at the right time (deduplicated)
|
|
10
|
+
* - Webhook ingestion: converts raw external payloads to RuntimeSignal
|
|
11
|
+
* - Routes all signals through the kernel SignalRouter for priority + dedup
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* const gateway = new SignalGateway()
|
|
15
|
+
* gateway.schedule(new ScheduledPrompt("summarize", Date.now() + 60_000))
|
|
16
|
+
* gateway.onSignal(sig => agent.ingestSignal(sig))
|
|
17
|
+
*/
|
|
18
|
+
export class SignalGateway {
|
|
19
|
+
timers = new Map();
|
|
20
|
+
listeners = [];
|
|
21
|
+
router = null;
|
|
22
|
+
async init() {
|
|
23
|
+
const kernel = await loadKernel();
|
|
24
|
+
this.router = new kernel.SignalRouter(1024);
|
|
25
|
+
}
|
|
26
|
+
onSignal(listener) {
|
|
27
|
+
this.listeners.push(listener);
|
|
28
|
+
}
|
|
29
|
+
/** Schedule a ScheduledPrompt to fire at its runAtMs. Idempotent by goal. */
|
|
30
|
+
schedule(prompt) {
|
|
31
|
+
const key = `cron:${prompt.goal}:${prompt.runAtMs}`;
|
|
32
|
+
if (this.timers.has(key))
|
|
33
|
+
return; // already scheduled
|
|
34
|
+
const delay = prompt.runAtMs - Date.now();
|
|
35
|
+
const fire = () => {
|
|
36
|
+
this.timers.delete(key);
|
|
37
|
+
this.emit({
|
|
38
|
+
kind: "scheduled",
|
|
39
|
+
payload: { goal: prompt.goal, criteria: prompt.criteria, runAtMs: prompt.runAtMs, ...prompt.metadata },
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
if (delay <= 0) {
|
|
43
|
+
fire();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
this.timers.set(key, setTimeout(fire, delay));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Cancel a scheduled prompt. */
|
|
50
|
+
cancel(goal, runAtMs) {
|
|
51
|
+
const key = `cron:${goal}:${runAtMs}`;
|
|
52
|
+
const t = this.timers.get(key);
|
|
53
|
+
if (t) {
|
|
54
|
+
clearTimeout(t);
|
|
55
|
+
this.timers.delete(key);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Ingest a raw external signal (e.g. from a webhook handler). */
|
|
59
|
+
ingest(sig) {
|
|
60
|
+
this.emit(sig);
|
|
61
|
+
}
|
|
62
|
+
emit(sig) {
|
|
63
|
+
for (const l of this.listeners)
|
|
64
|
+
l(sig);
|
|
65
|
+
}
|
|
66
|
+
destroy() {
|
|
67
|
+
for (const t of this.timers.values())
|
|
68
|
+
clearTimeout(t);
|
|
69
|
+
this.timers.clear();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RuntimeSignal } from "./types.js";
|
|
2
|
+
export declare class ScheduledPrompt {
|
|
3
|
+
readonly goal: string;
|
|
4
|
+
readonly runAtMs: number;
|
|
5
|
+
readonly criteria: string[];
|
|
6
|
+
readonly metadata: Record<string, unknown>;
|
|
7
|
+
constructor(goal: string, runAtMs: number, criteria?: string[], metadata?: Record<string, unknown>);
|
|
8
|
+
toSignal(): RuntimeSignal;
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class ScheduledPrompt {
|
|
2
|
+
goal;
|
|
3
|
+
runAtMs;
|
|
4
|
+
criteria;
|
|
5
|
+
metadata;
|
|
6
|
+
constructor(goal, runAtMs, criteria = [], metadata = {}) {
|
|
7
|
+
this.goal = goal;
|
|
8
|
+
this.runAtMs = runAtMs;
|
|
9
|
+
this.criteria = criteria;
|
|
10
|
+
this.metadata = metadata;
|
|
11
|
+
}
|
|
12
|
+
toSignal() {
|
|
13
|
+
return {
|
|
14
|
+
kind: "scheduled",
|
|
15
|
+
payload: { goal: this.goal, criteria: this.criteria, runAtMs: this.runAtMs, ...this.metadata },
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface SkillMetadata {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
whenToUse?: string;
|
|
5
|
+
effort?: number;
|
|
6
|
+
estimatedTokens?: number;
|
|
7
|
+
}
|
|
8
|
+
/** Read one skill file and return its full markdown content. */
|
|
9
|
+
export declare function readSkillFile(skillDir: string, name: string): Promise<string | null>;
|
|
10
|
+
/** Scan a skill directory and return frontmatter-only metadata for all `.md` files. */
|
|
11
|
+
export declare function scanSkillDir(skillDir: string): Promise<SkillMetadata[]>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readFile, readdir } from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
function parseFrontmatter(content) {
|
|
4
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
5
|
+
if (!match)
|
|
6
|
+
return { meta: {}, body: content };
|
|
7
|
+
const meta = {};
|
|
8
|
+
for (const line of match[1].split("\n")) {
|
|
9
|
+
const [k, ...v] = line.split(":");
|
|
10
|
+
if (k && v.length)
|
|
11
|
+
meta[k.trim()] = v.join(":").trim();
|
|
12
|
+
}
|
|
13
|
+
return { meta, body: match[2] };
|
|
14
|
+
}
|
|
15
|
+
/** Read one skill file and return its full markdown content. */
|
|
16
|
+
export async function readSkillFile(skillDir, name) {
|
|
17
|
+
try {
|
|
18
|
+
return await readFile(path.join(skillDir, `${name}.md`), "utf8");
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Scan a skill directory and return frontmatter-only metadata for all `.md` files. */
|
|
25
|
+
export async function scanSkillDir(skillDir) {
|
|
26
|
+
const files = await readdir(skillDir).catch(() => []);
|
|
27
|
+
const results = [];
|
|
28
|
+
for (const file of files.filter(f => f.endsWith(".md"))) {
|
|
29
|
+
const name = file.slice(0, -3);
|
|
30
|
+
const content = await readSkillFile(skillDir, name);
|
|
31
|
+
if (!content)
|
|
32
|
+
continue;
|
|
33
|
+
const { meta } = parseFrontmatter(content);
|
|
34
|
+
results.push({
|
|
35
|
+
name: meta.name ? String(meta.name) : name,
|
|
36
|
+
description: meta.description ? String(meta.description) : "",
|
|
37
|
+
whenToUse: meta.when_to_use ? String(meta.when_to_use) : undefined,
|
|
38
|
+
effort: meta.effort ? Number(meta.effort) : undefined,
|
|
39
|
+
estimatedTokens: meta.estimated_tokens ? Number(meta.estimated_tokens) : undefined,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return results;
|
|
43
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ToolSchema, ToolResult } from "../types.js";
|
|
2
|
+
export interface RegisteredTool {
|
|
3
|
+
schema: ToolSchema;
|
|
4
|
+
execute(args: Record<string, unknown>): Promise<string>;
|
|
5
|
+
}
|
|
6
|
+
export declare function tool(name: string, description: string, parameters: Record<string, unknown>, fn: (args: Record<string, unknown>) => Promise<string> | string): RegisteredTool;
|
|
7
|
+
export declare function executeTools(calls: {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
arguments: string;
|
|
11
|
+
}[], registry: Map<string, RegisteredTool>): Promise<ToolResult[]>;
|
|
12
|
+
export declare const readFile: RegisteredTool;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function tool(name, description, parameters, fn) {
|
|
2
|
+
return {
|
|
3
|
+
schema: { name, description, parameters: JSON.stringify(parameters) },
|
|
4
|
+
async execute(args) { return fn(args); },
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
export async function executeTools(calls, registry) {
|
|
8
|
+
return Promise.all(calls.map(async (c) => {
|
|
9
|
+
const t = registry.get(c.name);
|
|
10
|
+
if (!t)
|
|
11
|
+
return { callId: c.id, output: `unknown tool: ${c.name}`, isError: true };
|
|
12
|
+
try {
|
|
13
|
+
const args = JSON.parse(c.arguments || "{}");
|
|
14
|
+
const output = await t.execute(args);
|
|
15
|
+
return { callId: c.id, output, isError: false };
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
return { callId: c.id, output: String(err), isError: true };
|
|
19
|
+
}
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
export const readFile = tool("read_file", "Read the contents of a file.", { type: "object", properties: { path: { type: "string" } }, required: ["path"] }, async ({ path }) => {
|
|
23
|
+
const { readFile: fsRead } = await import("fs/promises");
|
|
24
|
+
return fsRead(String(path), "utf8");
|
|
25
|
+
});
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export interface Message {
|
|
2
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
3
|
+
content: string;
|
|
4
|
+
tokenCount?: number;
|
|
5
|
+
toolCalls?: ToolCall[];
|
|
6
|
+
}
|
|
7
|
+
export interface ToolCall {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
arguments: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ToolResult {
|
|
13
|
+
callId: string;
|
|
14
|
+
output: string;
|
|
15
|
+
isError: boolean;
|
|
16
|
+
tokenCount?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ToolSchema {
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
parameters: string;
|
|
22
|
+
}
|
|
23
|
+
export interface StreamEvent {
|
|
24
|
+
type: string;
|
|
25
|
+
}
|
|
26
|
+
export interface TextDelta extends StreamEvent {
|
|
27
|
+
type: "text_delta";
|
|
28
|
+
delta: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ThinkingDelta extends StreamEvent {
|
|
31
|
+
type: "thinking_delta";
|
|
32
|
+
delta: string;
|
|
33
|
+
}
|
|
34
|
+
export interface ToolCallEvent extends StreamEvent {
|
|
35
|
+
type: "tool_call";
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
arguments: Record<string, unknown>;
|
|
39
|
+
}
|
|
40
|
+
export interface ToolResultEvent extends StreamEvent {
|
|
41
|
+
type: "tool_result";
|
|
42
|
+
callId: string;
|
|
43
|
+
name: string;
|
|
44
|
+
content: string;
|
|
45
|
+
isError: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface DoneEvent extends StreamEvent {
|
|
48
|
+
type: "done";
|
|
49
|
+
iterations: number;
|
|
50
|
+
totalTokens: number;
|
|
51
|
+
status: string;
|
|
52
|
+
}
|
|
53
|
+
export interface ErrorEvent extends StreamEvent {
|
|
54
|
+
type: "error";
|
|
55
|
+
message: string;
|
|
56
|
+
}
|
|
57
|
+
export interface PermissionRequestEvent extends StreamEvent {
|
|
58
|
+
type: "permission_request";
|
|
59
|
+
callId: string;
|
|
60
|
+
toolName: string;
|
|
61
|
+
arguments: string;
|
|
62
|
+
reason: string;
|
|
63
|
+
}
|
|
64
|
+
export interface RetryConfig {
|
|
65
|
+
maxRetries?: number;
|
|
66
|
+
baseDelay?: number;
|
|
67
|
+
circuitOpenAfter?: number;
|
|
68
|
+
circuitResetAfter?: number;
|
|
69
|
+
}
|
|
70
|
+
export interface LLMProvider {
|
|
71
|
+
complete(messages: Message[], tools: ToolSchema[]): Promise<Message>;
|
|
72
|
+
stream(messages: Message[], tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
|
|
73
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@deepstrike/sdk",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "DeepStrike Node.js SDK",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": ["dist", "README.md"],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "node --experimental-vm-modules node_modules/.bin/jest"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@anthropic-ai/sdk": "^0.39.0",
|
|
15
|
+
"@deepstrike/core": "0.1.0",
|
|
16
|
+
"openai": "^4.77.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/jest": "^30.0.0",
|
|
20
|
+
"@types/node": "^22.0.0",
|
|
21
|
+
"jest": "^29.0.0",
|
|
22
|
+
"ts-jest": "^29.0.0",
|
|
23
|
+
"typescript": "^5.0.0"
|
|
24
|
+
}
|
|
25
|
+
}
|