@symplek/cli 0.0.0-stage → 0.2.0-beta.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/CHANGELOG.md +47 -0
- package/LICENSE +21 -0
- package/README.md +74 -2
- package/bin/symplek.js +5 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +44 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add.d.ts +36 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +467 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/generate.d.ts +26 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +491 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/init.d.ts +46 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +350 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/migrate.d.ts +41 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +518 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/validate.d.ts +252 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +515 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/models.d.ts +24 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +39 -0
- package/dist/models.js.map +1 -0
- package/dist/naming.d.ts +20 -0
- package/dist/naming.d.ts.map +1 -0
- package/dist/naming.js +48 -0
- package/dist/naming.js.map +1 -0
- package/dist/templates/agent/agent.ts.template +41 -0
- package/dist/templates/agent/general.yaml.template +34 -0
- package/dist/templates/agent/researcher.yaml.template +42 -0
- package/dist/templates/agent/reviewer.yaml.template +51 -0
- package/dist/templates/project/full/.github/workflows/ci.yml.template +34 -0
- package/dist/templates/project/full/.gitignore.template +6 -0
- package/dist/templates/project/full/Dockerfile.template +43 -0
- package/dist/templates/project/full/README.md.template +77 -0
- package/dist/templates/project/full/agents/example.yaml.template +16 -0
- package/dist/templates/project/full/package.json.template +30 -0
- package/dist/templates/project/full/src/index.ts.template +43 -0
- package/dist/templates/project/full/src/symplek.config.ts.template +20 -0
- package/dist/templates/project/full/src/tools/index.ts.template +73 -0
- package/dist/templates/project/full/tests/example.test.ts.template +49 -0
- package/dist/templates/project/full/tsconfig.json.template +18 -0
- package/dist/templates/project/minimal/.gitignore.template +6 -0
- package/dist/templates/project/minimal/agents/example.yaml.template +16 -0
- package/dist/templates/project/minimal/package.json.template +27 -0
- package/dist/templates/project/minimal/src/index.ts.template +43 -0
- package/dist/templates/project/minimal/src/symplek.config.ts.template +20 -0
- package/dist/templates/project/minimal/tsconfig.json.template +18 -0
- package/dist/templates/project/standard/.gitignore.template +6 -0
- package/dist/templates/project/standard/README.md.template +77 -0
- package/dist/templates/project/standard/agents/example.yaml.template +16 -0
- package/dist/templates/project/standard/package.json.template +30 -0
- package/dist/templates/project/standard/src/index.ts.template +43 -0
- package/dist/templates/project/standard/src/symplek.config.ts.template +20 -0
- package/dist/templates/project/standard/src/tools/index.ts.template +73 -0
- package/dist/templates/project/standard/tests/example.test.ts.template +49 -0
- package/dist/templates/project/standard/tsconfig.json.template +18 -0
- package/dist/utils/templates.d.ts +41 -0
- package/dist/utils/templates.d.ts.map +1 -0
- package/dist/utils/templates.js +133 -0
- package/dist/utils/templates.js.map +1 -0
- package/package.json +60 -3
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { AgentUnit, createContext, isTracked } from "@symplek/core";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { resilient, withProvenance } from "../src/tools/index.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Smoke tests for {{name}}'s tool helpers.
|
|
7
|
+
*
|
|
8
|
+
* These run without an API key — they exercise the operator algebra only,
|
|
9
|
+
* not real LLM calls. Add integration tests with `vi.mock("@symplek/core/server")`
|
|
10
|
+
* once you have agents that hit a provider.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
describe("{{name}} resilience helpers", () => {
|
|
14
|
+
it("returns the underlying value on success", async () => {
|
|
15
|
+
const ctx = createContext();
|
|
16
|
+
const unit = AgentUnit.of("ok");
|
|
17
|
+
const result = await resilient(unit, { maxAttempts: 1 }).run(ctx);
|
|
18
|
+
expect(result.value).toBe("ok");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("falls back to the supplied default when the unit fails", async () => {
|
|
22
|
+
const ctx = createContext();
|
|
23
|
+
const unit = AgentUnit.fail<string>(new Error("simulated failure"));
|
|
24
|
+
const result = await resilient(unit, { fallback: "safe-default" }).run(
|
|
25
|
+
ctx,
|
|
26
|
+
);
|
|
27
|
+
expect(result.value).toBe("safe-default");
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("{{name}} provenance helpers", () => {
|
|
32
|
+
it("wraps the value in a TrackedResult envelope", async () => {
|
|
33
|
+
const ctx = createContext();
|
|
34
|
+
const unit = AgentUnit.of("payload");
|
|
35
|
+
const result = await withProvenance(unit, {
|
|
36
|
+
source: "agent",
|
|
37
|
+
confidence: 0.95,
|
|
38
|
+
verifiedBy: "unit-test",
|
|
39
|
+
}).run(ctx);
|
|
40
|
+
|
|
41
|
+
// The result of .tracked() is itself a TrackedResult<TrackedResult<T>>
|
|
42
|
+
// — the outer envelope is added by .run() in zero-trust mode, the inner
|
|
43
|
+
// one is what `withProvenance` applied. We confirm both layers exist.
|
|
44
|
+
expect(result.value).toBeDefined();
|
|
45
|
+
expect(isTracked(result.value)).toBe(true);
|
|
46
|
+
expect(result.value.confidence).toBeCloseTo(0.95);
|
|
47
|
+
expect(result.value.source).toBe("agent");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": ".",
|
|
9
|
+
"strict": {{strict}},
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"declaration": false,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*", "agents/**/*"]
|
|
18
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Symplek agent definition — declarative form.
|
|
2
|
+
#
|
|
3
|
+
# Compile to TypeScript with:
|
|
4
|
+
# pnpm exec symplek generate
|
|
5
|
+
#
|
|
6
|
+
# This produces `agents/{{agentName}}.ts` that you can import and call
|
|
7
|
+
# from your application code. YAML lets non-engineers tune prompts without
|
|
8
|
+
# touching the source.
|
|
9
|
+
|
|
10
|
+
name: {{agentName}}
|
|
11
|
+
description: Summarises text in one clear sentence.
|
|
12
|
+
model: "{{model}}"
|
|
13
|
+
|
|
14
|
+
systemPrompt: |
|
|
15
|
+
You summarise the user's input in exactly one clear sentence.
|
|
16
|
+
Never embellish. Never editorialise. Faithful to the input only.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "{{version}}",
|
|
4
|
+
"description": "{{description}}",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": true,
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "tsx watch src/index.ts",
|
|
9
|
+
"start": "tsx src/index.ts",
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"typecheck": "tsc --noEmit"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@symplek/core": "^1.0.0-beta.1",
|
|
15
|
+
"zod": "^3.25.76",
|
|
16
|
+
"openai": "^4.104.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@symplek/cli": "^{{cliVersion}}",
|
|
20
|
+
"@types/node": "^22.14.0",
|
|
21
|
+
"tsx": "^4.19.0",
|
|
22
|
+
"typescript": "^5.9.0"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=20.19"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import "./symplek.config.js";
|
|
2
|
+
import { createContext } from "@symplek/core";
|
|
3
|
+
import { Symplek } from "@symplek/core/server";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* {{name}} — a minimal Symplek agent.
|
|
7
|
+
*
|
|
8
|
+
* Demonstrates the core pattern:
|
|
9
|
+
* 1. `Symplek(prompt)` builds an AI call.
|
|
10
|
+
* 2. `.coordinate()` lifts it into the AgentUnit<T> algebra.
|
|
11
|
+
* 3. Layer safety operators on top (retry, timeout, fallback, …).
|
|
12
|
+
* 4. `.run(ctx)` executes and returns a TrackedResult.
|
|
13
|
+
*
|
|
14
|
+
* Scripts:
|
|
15
|
+
* pnpm dev — watch mode (re-runs on file change)
|
|
16
|
+
* pnpm start — one-shot
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
20
|
+
console.error("[{{name}}] OPENAI_API_KEY is not set.");
|
|
21
|
+
console.error("Set it and re-run: export OPENAI_API_KEY=sk-...");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function main(): Promise<void> {
|
|
26
|
+
const ctx = createContext();
|
|
27
|
+
const input = "The quick brown fox jumps over the lazy dog.";
|
|
28
|
+
|
|
29
|
+
const result = await Symplek(`Summarise in one sentence: ${input}`)
|
|
30
|
+
.coordinate()
|
|
31
|
+
.retry(2)
|
|
32
|
+
.timeout(15_000)
|
|
33
|
+
.run(ctx);
|
|
34
|
+
|
|
35
|
+
console.log("Input: ", input);
|
|
36
|
+
console.log("Summary: ", result.value);
|
|
37
|
+
console.log("Confidence: ", result.confidence);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
main().catch((err: unknown) => {
|
|
41
|
+
console.error("[{{name}}] agent failed:", err);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symplek runtime configuration for {{name}}.
|
|
3
|
+
*
|
|
4
|
+
* Imported for side effect by `src/index.ts` before any agent runs.
|
|
5
|
+
* Set OPENAI_API_KEY in your environment:
|
|
6
|
+
*
|
|
7
|
+
* export OPENAI_API_KEY=sk-...
|
|
8
|
+
*
|
|
9
|
+
* To swap providers, change `provider` and the matching env var. Symplek
|
|
10
|
+
* supports `openai`, `anthropic`, and `google` out of the box — install
|
|
11
|
+
* the corresponding SDK (`pnpm add @anthropic-ai/sdk` etc.) and update
|
|
12
|
+
* this file.
|
|
13
|
+
*/
|
|
14
|
+
import { Symplek } from "@symplek/core/server";
|
|
15
|
+
|
|
16
|
+
Symplek.configure({
|
|
17
|
+
provider: "openai",
|
|
18
|
+
apiKey: process.env.OPENAI_API_KEY ?? "",
|
|
19
|
+
model: "{{model}}",
|
|
20
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": ".",
|
|
9
|
+
"strict": {{strict}},
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"declaration": false,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*", "agents/**/*"]
|
|
18
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# {{name}}
|
|
2
|
+
|
|
3
|
+
{{description}}
|
|
4
|
+
|
|
5
|
+
Built with [Symplek](https://github.com/symplek/symplek) — composable AI agents for TypeScript.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm install # or npm install / yarn / bun
|
|
13
|
+
export OPENAI_API_KEY=sk-... # provider env var from src/symplek.config.ts
|
|
14
|
+
pnpm dev # watch mode
|
|
15
|
+
pnpm start # one-shot
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
To switch providers, edit `src/symplek.config.ts` and install the matching SDK
|
|
19
|
+
(`pnpm add @anthropic-ai/sdk` for Anthropic, etc.). Symplek auto-detects which
|
|
20
|
+
provider is configured at runtime.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Project layout
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
{{name}}/
|
|
28
|
+
├── src/
|
|
29
|
+
│ ├── index.ts # entry — runs the example agent
|
|
30
|
+
│ ├── symplek.config.ts # Symplek runtime configuration (provider, API key)
|
|
31
|
+
│ └── tools/index.ts # composable helpers (resilient, withProvenance)
|
|
32
|
+
├── agents/
|
|
33
|
+
│ └── {{agentName}}.yaml # declarative agent — `symplek generate` compiles it
|
|
34
|
+
└── tests/
|
|
35
|
+
└── example.test.ts # vitest unit tests
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## What's where
|
|
41
|
+
|
|
42
|
+
- **`src/symplek.config.ts`** — registers your AI provider. Edit here to swap
|
|
43
|
+
OpenAI for Anthropic, change the default model, set a base URL, etc.
|
|
44
|
+
- **`src/tools/index.ts`** — your project's local helpers. Compose `AgentUnit`
|
|
45
|
+
operators into project-specific patterns here so the rest of your code stays
|
|
46
|
+
readable.
|
|
47
|
+
- **`agents/`** — YAML agent definitions. Run `symplek generate` to compile them
|
|
48
|
+
into typed TypeScript wrappers next to them, as `agents/<name>.ts`.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Scripts
|
|
53
|
+
|
|
54
|
+
| Command | What it does |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `pnpm dev` | Run the entry in watch mode via `tsx` |
|
|
57
|
+
| `pnpm start` | Run once |
|
|
58
|
+
| `pnpm build` | Compile TypeScript to `dist/` |
|
|
59
|
+
| `pnpm typecheck` | TypeScript check without emit |
|
|
60
|
+
| `pnpm test` | Run vitest once |
|
|
61
|
+
| `pnpm test:watch` | Run vitest in watch mode |
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Next steps
|
|
66
|
+
|
|
67
|
+
- Replace the example in `src/index.ts` with your real agent.
|
|
68
|
+
- Edit `agents/{{agentName}}.yaml`, then run `symplek generate` to add typed wrappers.
|
|
69
|
+
- Add more agents in `agents/`; the CLI handles wiring.
|
|
70
|
+
- See [github.com/symplek/symplek](https://github.com/symplek/symplek) for the operator
|
|
71
|
+
reference (consensus, debate, dialectic, rehearse, replay, supervised, etc.).
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
ISC
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Symplek agent definition — declarative form.
|
|
2
|
+
#
|
|
3
|
+
# Compile to TypeScript with:
|
|
4
|
+
# pnpm exec symplek generate
|
|
5
|
+
#
|
|
6
|
+
# This produces `agents/{{agentName}}.ts` that you can import and call
|
|
7
|
+
# from your application code. YAML lets non-engineers tune prompts without
|
|
8
|
+
# touching the source.
|
|
9
|
+
|
|
10
|
+
name: {{agentName}}
|
|
11
|
+
description: Summarises text in one clear sentence.
|
|
12
|
+
model: "{{model}}"
|
|
13
|
+
|
|
14
|
+
systemPrompt: |
|
|
15
|
+
You summarise the user's input in exactly one clear sentence.
|
|
16
|
+
Never embellish. Never editorialise. Faithful to the input only.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "{{version}}",
|
|
4
|
+
"description": "{{description}}",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": true,
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "tsx watch src/index.ts",
|
|
9
|
+
"start": "tsx src/index.ts",
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"typecheck": "tsc --noEmit",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"test:watch": "vitest"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@symplek/core": "^1.0.0-beta.1",
|
|
17
|
+
"zod": "^3.25.76",
|
|
18
|
+
"openai": "^4.104.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@symplek/cli": "^{{cliVersion}}",
|
|
22
|
+
"@types/node": "^22.14.0",
|
|
23
|
+
"tsx": "^4.19.0",
|
|
24
|
+
"typescript": "^5.9.0",
|
|
25
|
+
"vitest": "^2.1.0"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20.19"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import "./symplek.config.js";
|
|
2
|
+
import { createContext } from "@symplek/core";
|
|
3
|
+
import { Symplek } from "@symplek/core/server";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* {{name}} — a minimal Symplek agent.
|
|
7
|
+
*
|
|
8
|
+
* Demonstrates the core pattern:
|
|
9
|
+
* 1. `Symplek(prompt)` builds an AI call.
|
|
10
|
+
* 2. `.coordinate()` lifts it into the AgentUnit<T> algebra.
|
|
11
|
+
* 3. Layer safety operators on top (retry, timeout, fallback, …).
|
|
12
|
+
* 4. `.run(ctx)` executes and returns a TrackedResult.
|
|
13
|
+
*
|
|
14
|
+
* Scripts:
|
|
15
|
+
* pnpm dev — watch mode (re-runs on file change)
|
|
16
|
+
* pnpm start — one-shot
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
20
|
+
console.error("[{{name}}] OPENAI_API_KEY is not set.");
|
|
21
|
+
console.error("Set it and re-run: export OPENAI_API_KEY=sk-...");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function main(): Promise<void> {
|
|
26
|
+
const ctx = createContext();
|
|
27
|
+
const input = "The quick brown fox jumps over the lazy dog.";
|
|
28
|
+
|
|
29
|
+
const result = await Symplek(`Summarise in one sentence: ${input}`)
|
|
30
|
+
.coordinate()
|
|
31
|
+
.retry(2)
|
|
32
|
+
.timeout(15_000)
|
|
33
|
+
.run(ctx);
|
|
34
|
+
|
|
35
|
+
console.log("Input: ", input);
|
|
36
|
+
console.log("Summary: ", result.value);
|
|
37
|
+
console.log("Confidence: ", result.confidence);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
main().catch((err: unknown) => {
|
|
41
|
+
console.error("[{{name}}] agent failed:", err);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symplek runtime configuration for {{name}}.
|
|
3
|
+
*
|
|
4
|
+
* Imported for side effect by `src/index.ts` before any agent runs.
|
|
5
|
+
* Set OPENAI_API_KEY in your environment:
|
|
6
|
+
*
|
|
7
|
+
* export OPENAI_API_KEY=sk-...
|
|
8
|
+
*
|
|
9
|
+
* To swap providers, change `provider` and the matching env var. Symplek
|
|
10
|
+
* supports `openai`, `anthropic`, and `google` out of the box — install
|
|
11
|
+
* the corresponding SDK (`pnpm add @anthropic-ai/sdk` etc.) and update
|
|
12
|
+
* this file.
|
|
13
|
+
*/
|
|
14
|
+
import { Symplek } from "@symplek/core/server";
|
|
15
|
+
|
|
16
|
+
Symplek.configure({
|
|
17
|
+
provider: "openai",
|
|
18
|
+
apiKey: process.env.OPENAI_API_KEY ?? "",
|
|
19
|
+
model: "{{model}}",
|
|
20
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-local helpers for {{name}}.
|
|
3
|
+
*
|
|
4
|
+
* Compose Symplek operators into patterns specific to your project here so
|
|
5
|
+
* your business code stays declarative. Each helper is one operator chain.
|
|
6
|
+
*/
|
|
7
|
+
import {
|
|
8
|
+
type AgentUnit,
|
|
9
|
+
isTracked,
|
|
10
|
+
type ResultSource,
|
|
11
|
+
type TrackedResult,
|
|
12
|
+
} from "@symplek/core";
|
|
13
|
+
|
|
14
|
+
export interface ProvenanceOptions {
|
|
15
|
+
/** Source category — one of Symplek's `ResultSource` literals. */
|
|
16
|
+
source: ResultSource;
|
|
17
|
+
/** Caller's confidence in this value, in [0, 1]. */
|
|
18
|
+
confidence: number;
|
|
19
|
+
/** Optional identifier of the verifier (audit trail). */
|
|
20
|
+
verifiedBy?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Wrap an `AgentUnit<T>` so its output carries provenance metadata.
|
|
25
|
+
*
|
|
26
|
+
* Downstream callers can introspect `result.value`, `result.source`,
|
|
27
|
+
* `result.confidence` — Symplek's TrackedResult shape — without any extra
|
|
28
|
+
* plumbing.
|
|
29
|
+
*/
|
|
30
|
+
export function withProvenance<T>(
|
|
31
|
+
unit: AgentUnit<T>,
|
|
32
|
+
opts: ProvenanceOptions,
|
|
33
|
+
): AgentUnit<TrackedResult<T>> {
|
|
34
|
+
return unit.tracked({
|
|
35
|
+
source: opts.source,
|
|
36
|
+
confidence: opts.confidence,
|
|
37
|
+
verifiedBy: opts.verifiedBy,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ResilienceOptions<T> {
|
|
42
|
+
/** Max attempts including the first. Default 3. */
|
|
43
|
+
maxAttempts?: number;
|
|
44
|
+
/** Hard timeout in milliseconds. Default 15s. */
|
|
45
|
+
timeoutMs?: number;
|
|
46
|
+
/** Static fallback value if all attempts fail. */
|
|
47
|
+
fallback?: T;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Apply the standard resilience triad: retry on transient failure, hard
|
|
52
|
+
* timeout, fallback to a known-safe value if all else fails.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* const safe = resilient(
|
|
56
|
+
* Symplek(prompt).coordinate(),
|
|
57
|
+
* { maxAttempts: 3, timeoutMs: 10_000, fallback: "" },
|
|
58
|
+
* );
|
|
59
|
+
*/
|
|
60
|
+
export function resilient<T>(
|
|
61
|
+
unit: AgentUnit<T>,
|
|
62
|
+
options: ResilienceOptions<T> = {},
|
|
63
|
+
): AgentUnit<T> {
|
|
64
|
+
const { maxAttempts = 3, timeoutMs = 15_000, fallback } = options;
|
|
65
|
+
let chain = unit.retry(maxAttempts).timeout(timeoutMs);
|
|
66
|
+
if (fallback !== undefined) {
|
|
67
|
+
chain = chain.orElse(fallback);
|
|
68
|
+
}
|
|
69
|
+
return chain;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Re-export Symplek's tracked-result type guard for convenience. */
|
|
73
|
+
export { isTracked };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { AgentUnit, createContext, isTracked } from "@symplek/core";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { resilient, withProvenance } from "../src/tools/index.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Smoke tests for {{name}}'s tool helpers.
|
|
7
|
+
*
|
|
8
|
+
* These run without an API key — they exercise the operator algebra only,
|
|
9
|
+
* not real LLM calls. Add integration tests with `vi.mock("@symplek/core/server")`
|
|
10
|
+
* once you have agents that hit a provider.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
describe("{{name}} resilience helpers", () => {
|
|
14
|
+
it("returns the underlying value on success", async () => {
|
|
15
|
+
const ctx = createContext();
|
|
16
|
+
const unit = AgentUnit.of("ok");
|
|
17
|
+
const result = await resilient(unit, { maxAttempts: 1 }).run(ctx);
|
|
18
|
+
expect(result.value).toBe("ok");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("falls back to the supplied default when the unit fails", async () => {
|
|
22
|
+
const ctx = createContext();
|
|
23
|
+
const unit = AgentUnit.fail<string>(new Error("simulated failure"));
|
|
24
|
+
const result = await resilient(unit, { fallback: "safe-default" }).run(
|
|
25
|
+
ctx,
|
|
26
|
+
);
|
|
27
|
+
expect(result.value).toBe("safe-default");
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("{{name}} provenance helpers", () => {
|
|
32
|
+
it("wraps the value in a TrackedResult envelope", async () => {
|
|
33
|
+
const ctx = createContext();
|
|
34
|
+
const unit = AgentUnit.of("payload");
|
|
35
|
+
const result = await withProvenance(unit, {
|
|
36
|
+
source: "agent",
|
|
37
|
+
confidence: 0.95,
|
|
38
|
+
verifiedBy: "unit-test",
|
|
39
|
+
}).run(ctx);
|
|
40
|
+
|
|
41
|
+
// The result of .tracked() is itself a TrackedResult<TrackedResult<T>>
|
|
42
|
+
// — the outer envelope is added by .run() in zero-trust mode, the inner
|
|
43
|
+
// one is what `withProvenance` applied. We confirm both layers exist.
|
|
44
|
+
expect(result.value).toBeDefined();
|
|
45
|
+
expect(isTracked(result.value)).toBe(true);
|
|
46
|
+
expect(result.value.confidence).toBeCloseTo(0.95);
|
|
47
|
+
expect(result.value.source).toBe("agent");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": ".",
|
|
9
|
+
"strict": {{strict}},
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"declaration": false,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*", "agents/**/*"]
|
|
18
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Available project template tiers */
|
|
2
|
+
export type ProjectTier = "minimal" | "standard" | "full";
|
|
3
|
+
/** Available agent template types */
|
|
4
|
+
export type AgentType = "general" | "researcher" | "reviewer" | "typescript";
|
|
5
|
+
/** Template variable map */
|
|
6
|
+
export type TemplateVars = Record<string, string>;
|
|
7
|
+
/**
|
|
8
|
+
* Process a template string by replacing {{variableName}} with actual values
|
|
9
|
+
* Unmatched variables are preserved as-is
|
|
10
|
+
*/
|
|
11
|
+
export declare function processTemplate(content: string, vars: TemplateVars): string;
|
|
12
|
+
/**
|
|
13
|
+
* Get the absolute path to a project template file
|
|
14
|
+
*/
|
|
15
|
+
export declare function getProjectTemplatePath(tier: ProjectTier, ...pathSegments: string[]): string;
|
|
16
|
+
/**
|
|
17
|
+
* Get the absolute path to an agent template file
|
|
18
|
+
*/
|
|
19
|
+
export declare function getAgentTemplatePath(filename: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Load a project template file and process it with variables
|
|
22
|
+
*/
|
|
23
|
+
export declare function loadProjectTemplate(tier: ProjectTier, pathSegments: string[], vars?: TemplateVars): string;
|
|
24
|
+
/**
|
|
25
|
+
* Load an agent template file and process it with variables
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadAgentTemplate(type: AgentType, vars?: TemplateVars): string;
|
|
28
|
+
/**
|
|
29
|
+
* Get the templates root directory path
|
|
30
|
+
*/
|
|
31
|
+
export declare function getTemplatesRoot(): string;
|
|
32
|
+
/**
|
|
33
|
+
* Get list of files for a project tier
|
|
34
|
+
* Higher tiers inherit from lower tiers
|
|
35
|
+
*/
|
|
36
|
+
export declare function getProjectTierFiles(tier: ProjectTier): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Default template variables with sensible defaults
|
|
39
|
+
*/
|
|
40
|
+
export declare function getDefaultVars(name: string): TemplateVars;
|
|
41
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/utils/templates.ts"],"names":[],"mappings":"AAcA,uCAAuC;AACvC,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAE1D,qCAAqC;AACrC,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,GAAG,YAAY,CAAC;AAE7E,4BAA4B;AAC5B,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAE3E;AAkBD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,GAAG,YAAY,EAAE,MAAM,EAAE,GACxB,MAAM,CAER;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,MAAM,EAAE,EACtB,IAAI,GAAE,YAAiB,GACtB,MAAM,CASR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,EACf,IAAI,GAAE,YAAiB,GACtB,MAAM,CAWR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,EAAE,CA8B/D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAYzD"}
|