@vraxis/agent-v 0.4.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.
Files changed (119) hide show
  1. package/AGENTS.md +61 -0
  2. package/ARCHITECTURE.md +148 -0
  3. package/CHANGELOG.md +25 -0
  4. package/LICENSE +21 -0
  5. package/README.md +237 -0
  6. package/compatibility.json +41 -0
  7. package/dist/adapters/ai-sdk/index.d.ts +46 -0
  8. package/dist/adapters/ai-sdk/index.d.ts.map +1 -0
  9. package/dist/adapters/ai-sdk/index.js +383 -0
  10. package/dist/adapters/ai-sdk/index.js.map +1 -0
  11. package/dist/adapters/local-cli/definitions.d.ts +22 -0
  12. package/dist/adapters/local-cli/definitions.d.ts.map +1 -0
  13. package/dist/adapters/local-cli/definitions.js +72 -0
  14. package/dist/adapters/local-cli/definitions.js.map +1 -0
  15. package/dist/adapters/local-cli/engine.d.ts +26 -0
  16. package/dist/adapters/local-cli/engine.d.ts.map +1 -0
  17. package/dist/adapters/local-cli/engine.js +200 -0
  18. package/dist/adapters/local-cli/engine.js.map +1 -0
  19. package/dist/adapters/local-cli/index.d.ts +6 -0
  20. package/dist/adapters/local-cli/index.d.ts.map +1 -0
  21. package/dist/adapters/local-cli/index.js +6 -0
  22. package/dist/adapters/local-cli/index.js.map +1 -0
  23. package/dist/adapters/local-cli/parsing.d.ts +7 -0
  24. package/dist/adapters/local-cli/parsing.d.ts.map +1 -0
  25. package/dist/adapters/local-cli/parsing.js +95 -0
  26. package/dist/adapters/local-cli/parsing.js.map +1 -0
  27. package/dist/adapters/local-cli/process.d.ts +12 -0
  28. package/dist/adapters/local-cli/process.d.ts.map +1 -0
  29. package/dist/adapters/local-cli/process.js +19 -0
  30. package/dist/adapters/local-cli/process.js.map +1 -0
  31. package/dist/adapters/local-cli/store.d.ts +11 -0
  32. package/dist/adapters/local-cli/store.d.ts.map +1 -0
  33. package/dist/adapters/local-cli/store.js +11 -0
  34. package/dist/adapters/local-cli/store.js.map +1 -0
  35. package/dist/adapters/ollama/index.d.ts +45 -0
  36. package/dist/adapters/ollama/index.d.ts.map +1 -0
  37. package/dist/adapters/ollama/index.js +155 -0
  38. package/dist/adapters/ollama/index.js.map +1 -0
  39. package/dist/cli/index.d.ts +3 -0
  40. package/dist/cli/index.d.ts.map +1 -0
  41. package/dist/cli/index.js +116 -0
  42. package/dist/cli/index.js.map +1 -0
  43. package/dist/core/agent-v.d.ts +29 -0
  44. package/dist/core/agent-v.d.ts.map +1 -0
  45. package/dist/core/agent-v.js +153 -0
  46. package/dist/core/agent-v.js.map +1 -0
  47. package/dist/core/config.d.ts +31 -0
  48. package/dist/core/config.d.ts.map +1 -0
  49. package/dist/core/config.js +21 -0
  50. package/dist/core/config.js.map +1 -0
  51. package/dist/core/contracts.d.ts +135 -0
  52. package/dist/core/contracts.d.ts.map +1 -0
  53. package/dist/core/contracts.js +2 -0
  54. package/dist/core/contracts.js.map +1 -0
  55. package/dist/core/errors.d.ts +12 -0
  56. package/dist/core/errors.d.ts.map +1 -0
  57. package/dist/core/errors.js +27 -0
  58. package/dist/core/errors.js.map +1 -0
  59. package/dist/core/events.d.ts +74 -0
  60. package/dist/core/events.d.ts.map +1 -0
  61. package/dist/core/events.js +14 -0
  62. package/dist/core/events.js.map +1 -0
  63. package/dist/core/extensions.d.ts +80 -0
  64. package/dist/core/extensions.d.ts.map +1 -0
  65. package/dist/core/extensions.js +77 -0
  66. package/dist/core/extensions.js.map +1 -0
  67. package/dist/core/index.d.ts +12 -0
  68. package/dist/core/index.d.ts.map +1 -0
  69. package/dist/core/index.js +12 -0
  70. package/dist/core/index.js.map +1 -0
  71. package/dist/core/memory.d.ts +15 -0
  72. package/dist/core/memory.d.ts.map +1 -0
  73. package/dist/core/memory.js +21 -0
  74. package/dist/core/memory.js.map +1 -0
  75. package/dist/core/output.d.ts +10 -0
  76. package/dist/core/output.d.ts.map +1 -0
  77. package/dist/core/output.js +15 -0
  78. package/dist/core/output.js.map +1 -0
  79. package/dist/core/registry.d.ts +13 -0
  80. package/dist/core/registry.d.ts.map +1 -0
  81. package/dist/core/registry.js +29 -0
  82. package/dist/core/registry.js.map +1 -0
  83. package/dist/core/types.d.ts +141 -0
  84. package/dist/core/types.d.ts.map +1 -0
  85. package/dist/core/types.js +21 -0
  86. package/dist/core/types.js.map +1 -0
  87. package/dist/core/version.d.ts +3 -0
  88. package/dist/core/version.d.ts.map +1 -0
  89. package/dist/core/version.js +3 -0
  90. package/dist/core/version.js.map +1 -0
  91. package/dist/node/doctor.d.ts +50 -0
  92. package/dist/node/doctor.d.ts.map +1 -0
  93. package/dist/node/doctor.js +121 -0
  94. package/dist/node/doctor.js.map +1 -0
  95. package/dist/node/index.d.ts +26 -0
  96. package/dist/node/index.d.ts.map +1 -0
  97. package/dist/node/index.js +84 -0
  98. package/dist/node/index.js.map +1 -0
  99. package/dist/node/skills.d.ts +12 -0
  100. package/dist/node/skills.d.ts.map +1 -0
  101. package/dist/node/skills.js +96 -0
  102. package/dist/node/skills.js.map +1 -0
  103. package/dist/testing/index.d.ts +25 -0
  104. package/dist/testing/index.d.ts.map +1 -0
  105. package/dist/testing/index.js +33 -0
  106. package/dist/testing/index.js.map +1 -0
  107. package/examples/approved-tool.ts +56 -0
  108. package/examples/basic-ai-sdk.ts +29 -0
  109. package/examples/custom-model-resolver.ts +14 -0
  110. package/examples/filesystem-skill.ts +12 -0
  111. package/examples/local-cli.ts +28 -0
  112. package/examples/ollama.ts +15 -0
  113. package/examples/sessions-and-events.ts +18 -0
  114. package/examples/smoke.ts +35 -0
  115. package/examples/tsconfig.json +16 -0
  116. package/llms.txt +13 -0
  117. package/package.json +97 -0
  118. package/skills/agent-v/SKILL.md +39 -0
  119. package/skills/agent-v/references/integration-patterns.md +57 -0
@@ -0,0 +1,96 @@
1
+ import { readdir, readFile, realpath } from "node:fs/promises";
2
+ import { basename, join } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { parseDocument } from "yaml";
5
+ import { AgentVError } from "../core/index.js";
6
+ function invalid(message) {
7
+ throw new AgentVError("configuration-invalid", `Invalid Agent Skill: ${message}`);
8
+ }
9
+ function optionalString(value, field, max) {
10
+ if (value === undefined)
11
+ return undefined;
12
+ if (typeof value !== "string" || !value.trim() || value.length > max)
13
+ invalid(`${field} must be a non-empty string no longer than ${max} characters.`);
14
+ return value;
15
+ }
16
+ function metadata(value) {
17
+ if (value === undefined)
18
+ return undefined;
19
+ if (!value || typeof value !== "object" || Array.isArray(value))
20
+ invalid("metadata must be a string-to-string mapping.");
21
+ const entries = Object.entries(value);
22
+ if (entries.some(([, item]) => typeof item !== "string"))
23
+ invalid("metadata values must be strings.");
24
+ return Object.fromEntries(entries);
25
+ }
26
+ async function files(directory) {
27
+ try {
28
+ const entries = await readdir(directory, { withFileTypes: true });
29
+ return entries.filter((entry) => entry.isFile()).map((entry) => join(directory, entry.name)).sort();
30
+ }
31
+ catch (error) {
32
+ if (error.code === "ENOENT")
33
+ return [];
34
+ throw error;
35
+ }
36
+ }
37
+ export async function loadSkillPackage(directory) {
38
+ const rootPath = await realpath(directory).catch((error) => {
39
+ if (error.code === "ENOENT")
40
+ invalid(`directory does not exist: ${directory}`);
41
+ throw error;
42
+ });
43
+ const manifestPath = join(rootPath, "SKILL.md");
44
+ const source = await readFile(manifestPath, "utf8").catch((error) => {
45
+ if (error.code === "ENOENT")
46
+ invalid(`SKILL.md is missing from ${rootPath}`);
47
+ throw error;
48
+ });
49
+ const match = source.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/);
50
+ if (!match)
51
+ invalid("SKILL.md must contain YAML frontmatter followed by Markdown instructions.");
52
+ const document = parseDocument(match[1], { prettyErrors: true, uniqueKeys: true });
53
+ if (document.errors.length)
54
+ invalid(document.errors.map((error) => error.message).join("; "));
55
+ const frontmatter = document.toJS();
56
+ const name = optionalString(frontmatter.name, "name", 64) ?? invalid("name is required.");
57
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name))
58
+ invalid("name must contain lowercase letters, numbers, and single hyphens only.");
59
+ if (name !== basename(rootPath))
60
+ invalid(`name ${name} must match its parent directory name ${basename(rootPath)}.`);
61
+ const description = optionalString(frontmatter.description, "description", 1024) ?? invalid("description is required.");
62
+ const compatibility = optionalString(frontmatter.compatibility, "compatibility", 500);
63
+ const license = optionalString(frontmatter.license, "license", 500);
64
+ const parsedMetadata = metadata(frontmatter.metadata);
65
+ const allowedToolsRaw = optionalString(frontmatter["allowed-tools"], "allowed-tools", 2048);
66
+ const preapprovedTools = allowedToolsRaw?.match(/\S+/g) ?? [];
67
+ const instructions = match[2].trim();
68
+ if (!instructions)
69
+ invalid("the Markdown instruction body must not be empty.");
70
+ return {
71
+ rootPath,
72
+ manifestPath,
73
+ skill: {
74
+ id: name,
75
+ name,
76
+ version: typeof parsedMetadata?.version === "string" ? parsedMetadata.version : "0.0.0",
77
+ description,
78
+ instructions,
79
+ tools: preapprovedTools,
80
+ preapprovedTools,
81
+ license,
82
+ compatibility,
83
+ metadata: parsedMetadata,
84
+ source: { format: "agent-skills", uri: pathToFileURL(manifestPath).href },
85
+ },
86
+ scripts: await files(join(rootPath, "scripts")),
87
+ references: await files(join(rootPath, "references")),
88
+ assets: await files(join(rootPath, "assets")),
89
+ };
90
+ }
91
+ export async function discoverSkillPackages(parentDirectory) {
92
+ const entries = await readdir(parentDirectory, { withFileTypes: true });
93
+ const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => join(parentDirectory, entry.name)).sort();
94
+ return Promise.all(directories.map(loadSkillPackage));
95
+ }
96
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/node/skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { ApprovalPolicy, ApprovalRequest, StructuredGenerationRequest, StructuredGenerationResult, StructuredModelEngine, ToolAgentEngine, ToolAgentRequest, ToolAgentResult } from "../core/contracts.js";
2
+ import { type EventSink } from "../core/events.js";
3
+ import type { EngineDescriptor } from "../core/types.js";
4
+ export declare class StaticApprovalPolicy implements ApprovalPolicy {
5
+ private readonly decision;
6
+ readonly requests: ApprovalRequest[];
7
+ constructor(decision: "approved" | "denied");
8
+ decide(request: ApprovalRequest): Promise<"approved" | "denied">;
9
+ }
10
+ export declare class FakeStructuredModelEngine implements StructuredModelEngine {
11
+ private readonly response;
12
+ readonly descriptor: EngineDescriptor;
13
+ constructor(response: unknown);
14
+ generate<T>(request: StructuredGenerationRequest<T>, _events?: EventSink): Promise<StructuredGenerationResult<T>>;
15
+ }
16
+ export declare class FakeToolAgentEngine implements ToolAgentEngine {
17
+ readonly descriptor: EngineDescriptor;
18
+ readonly requests: ToolAgentRequest<unknown>[];
19
+ run<T = string>(request: ToolAgentRequest<T>, events?: EventSink): Promise<ToolAgentResult<T>>;
20
+ stream<T = string>(request: ToolAgentRequest<T>, events?: EventSink): Promise<{
21
+ events: AsyncGenerator<never, void, unknown>;
22
+ result: Promise<ToolAgentResult<T>>;
23
+ }>;
24
+ }
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,2BAA2B,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAChN,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,qBAAa,oBAAqB,YAAW,cAAc;IAE7C,OAAO,CAAC,QAAQ,CAAC,QAAQ;IADrC,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAM;gBACb,QAAQ,EAAE,UAAU,GAAG,QAAQ;IACtD,MAAM,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,GAAG,QAAQ,CAAC;CACvE;AAED,qBAAa,yBAA0B,YAAW,qBAAqB;IAEzD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IADrC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAA2G;gBACnH,QAAQ,EAAE,OAAO;IACxC,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,2BAA2B,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC;CAGxH;AAED,qBAAa,mBAAoB,YAAW,eAAe;IACzD,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAwH;IAC7J,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAM;IAC9C,GAAG,CAAC,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,GAAE,SAAyB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAQ7G,MAAM,CAAC,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,SAAS;;;;CAC1E"}
@@ -0,0 +1,33 @@
1
+ import { eventTimestamp, noopEventSink } from "../core/events.js";
2
+ export class StaticApprovalPolicy {
3
+ decision;
4
+ requests = [];
5
+ constructor(decision) {
6
+ this.decision = decision;
7
+ }
8
+ async decide(request) { this.requests.push(request); return this.decision; }
9
+ }
10
+ export class FakeStructuredModelEngine {
11
+ response;
12
+ descriptor = { id: "fake-model", name: "Fake model", kind: "structured-model", capabilities: ["structured-output"] };
13
+ constructor(response) {
14
+ this.response = response;
15
+ }
16
+ async generate(request, _events) {
17
+ return { runId: request.runId ?? "fake-run", output: request.output.parse(this.response), provenance: { engineId: this.descriptor.id, adapterStrategy: "fake-structured-v1" }, durationMs: 0 };
18
+ }
19
+ }
20
+ export class FakeToolAgentEngine {
21
+ descriptor = { id: "fake-agent", name: "Fake agent", kind: "tool-agent", capabilities: ["tools", "skills", "structured-output"] };
22
+ requests = [];
23
+ async run(request, events = noopEventSink) {
24
+ this.requests.push(request);
25
+ const runId = request.runId ?? "fake-run";
26
+ await events.emit({ type: "run.started", runId, timestamp: eventTimestamp(), scope: request.scope, provenance: { engineId: this.descriptor.id, adapterStrategy: "fake-tool-agent-v1" } });
27
+ const output = request.output ? request.output.parse({ ok: true }) : "ok";
28
+ await events.emit({ type: "run.completed", runId, timestamp: eventTimestamp(), scope: request.scope, durationMs: 0 });
29
+ return { runId, output, text: "ok", steps: 1, provenance: { engineId: this.descriptor.id, adapterStrategy: "fake-tool-agent-v1" }, durationMs: 0 };
30
+ }
31
+ async stream(request, events) { return { events: (async function* () { })(), result: this.run(request, events) }; }
32
+ }
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import {
2
+ defineOutput,
3
+ defineTool,
4
+ type ApprovalPolicy,
5
+ } from "@vraxis/agent-v";
6
+
7
+ export const explicitApproval: ApprovalPolicy = {
8
+ async decide(request) {
9
+ // Replace this example decision with the host application's reviewed UI state.
10
+ return request.metadata?.founderApproved === true ? "approved" : "denied";
11
+ },
12
+ };
13
+
14
+ export function createPublishContributionTool(publish: (body: string) => Promise<{ channelId: string }>) {
15
+ return defineTool({
16
+ name: "publish-contribution",
17
+ version: "1.0.0",
18
+ description: "Publish one reviewed contribution through the selected channel.",
19
+ input: defineOutput({
20
+ name: "publish-contribution-input",
21
+ jsonSchema: {
22
+ type: "object",
23
+ properties: { body: { type: "string" } },
24
+ required: ["body"],
25
+ additionalProperties: false,
26
+ },
27
+ parse(value) {
28
+ const body = (value as { body?: unknown }).body;
29
+ if (typeof body !== "string" || !body.trim()) throw new Error("body is required");
30
+ return { body };
31
+ },
32
+ }),
33
+ output: defineOutput({
34
+ name: "publish-contribution-output",
35
+ jsonSchema: {
36
+ type: "object",
37
+ properties: { channelId: { type: "string" } },
38
+ required: ["channelId"],
39
+ additionalProperties: false,
40
+ },
41
+ parse(value) {
42
+ const channelId = (value as { channelId?: unknown }).channelId;
43
+ if (typeof channelId !== "string" || !channelId) throw new Error("channelId is required");
44
+ return { channelId };
45
+ },
46
+ }),
47
+ risk: "external-side-effect",
48
+ sideEffect: "non-idempotent",
49
+ requiredPermissions: ["contributions:publish"],
50
+ requiresApproval: true,
51
+ timeoutMs: 15_000,
52
+ execute({ body }) {
53
+ return publish(body);
54
+ },
55
+ });
56
+ }
@@ -0,0 +1,29 @@
1
+ import type { LanguageModel } from "ai";
2
+ import {
3
+ AgentV,
4
+ EngineRegistry,
5
+ defineAgent,
6
+ localExecutionScope,
7
+ } from "@vraxis/agent-v";
8
+ import { AiSdkToolAgentEngine } from "@vraxis/agent-v/ai-sdk";
9
+
10
+ export function createBasicAiAgent(model: LanguageModel) {
11
+ const engine = new AiSdkToolAgentEngine({
12
+ id: "primary-agent",
13
+ name: "Primary AI agent",
14
+ model,
15
+ adapterStrategy: "example-ai-sdk-v7",
16
+ });
17
+ const runtime = new AgentV({ engines: new EngineRegistry().register(engine) });
18
+ const agent = defineAgent({
19
+ id: "assistant",
20
+ name: "Assistant",
21
+ engineId: engine.descriptor.id,
22
+ instructions: "Answer clearly using only the context supplied by the host.",
23
+ skills: [],
24
+ tools: [],
25
+ requiredCapabilities: ["streaming"],
26
+ maxSteps: 8,
27
+ });
28
+ return { runtime, agent, scope: localExecutionScope("example-app") };
29
+ }
@@ -0,0 +1,14 @@
1
+ import { AiSdkToolAgentEngine, type AiSdkModelResolver } from "@vraxis/agent-v/ai-sdk";
2
+
3
+ export function createResolvedModelEngine(resolveModel: AiSdkModelResolver) {
4
+ return new AiSdkToolAgentEngine({
5
+ id: "profiled-agent",
6
+ name: "Profile-resolved agent",
7
+ provider: "host-resolved",
8
+ adapterStrategy: "host-model-resolver-v1",
9
+ resolveModel,
10
+ });
11
+ }
12
+
13
+ // A resolver should use selection.credentialRef and selection.scope to obtain
14
+ // a provider model without placing credential values in agent-v configuration.
@@ -0,0 +1,12 @@
1
+ import { ExtensionRegistry, defineExtension } from "@vraxis/agent-v";
2
+ import { loadSkillPackage } from "@vraxis/agent-v/node";
3
+
4
+ export async function registerFilesystemSkill(directory: string, extensions = new ExtensionRegistry()) {
5
+ const loaded = await loadSkillPackage(directory);
6
+ extensions.use(defineExtension({
7
+ id: `${loaded.skill.id}-package`,
8
+ version: loaded.skill.version,
9
+ skills: [loaded.skill],
10
+ }));
11
+ return { extensions, loaded };
12
+ }
@@ -0,0 +1,28 @@
1
+ import { defineOutput, localExecutionScope } from "@vraxis/agent-v";
2
+ import { LocalCliRuntimeEngine } from "@vraxis/agent-v/local-cli";
3
+
4
+ export function createRepositorySummaryRequest(workspacePath: string) {
5
+ const engine = new LocalCliRuntimeEngine();
6
+ const request = {
7
+ runtimeId: "codex",
8
+ workspacePath,
9
+ workspaceAccess: "read-only" as const,
10
+ scope: localExecutionScope("repository-summary"),
11
+ input: { prompt: "Summarize the repository architecture using only evidence in the workspace." },
12
+ output: defineOutput({
13
+ name: "repository-summary",
14
+ jsonSchema: {
15
+ type: "object",
16
+ properties: { summary: { type: "string" } },
17
+ required: ["summary"],
18
+ additionalProperties: false,
19
+ },
20
+ parse(value) {
21
+ const summary = (value as { summary?: unknown }).summary;
22
+ if (typeof summary !== "string") throw new Error("summary is required");
23
+ return { summary };
24
+ },
25
+ }),
26
+ };
27
+ return { engine, request };
28
+ }
@@ -0,0 +1,15 @@
1
+ import { EngineRegistry } from "@vraxis/agent-v";
2
+ import { OllamaRuntime } from "@vraxis/agent-v/ollama";
3
+
4
+ export function createLocalOllama(model: string, baseURL = "http://127.0.0.1:11434") {
5
+ const ollama = new OllamaRuntime({ defaultModel: model, baseURL });
6
+ return {
7
+ ollama,
8
+ async registerWhenReady(engines: EngineRegistry) {
9
+ const readiness = await ollama.inspect();
10
+ if (readiness.availability !== "ready") return readiness;
11
+ engines.register(ollama.agent).register(ollama.structured);
12
+ return readiness;
13
+ },
14
+ };
15
+ }
@@ -0,0 +1,18 @@
1
+ import {
2
+ AgentV,
3
+ EngineRegistry,
4
+ MemoryRunEventStore,
5
+ MemorySessionStore,
6
+ type ToolAgentEngine,
7
+ } from "@vraxis/agent-v";
8
+
9
+ export function createStatefulRuntime(engine: ToolAgentEngine) {
10
+ const sessions = new MemorySessionStore();
11
+ const runEvents = new MemoryRunEventStore();
12
+ const runtime = new AgentV({
13
+ engines: new EngineRegistry().register(engine),
14
+ sessions,
15
+ runEvents,
16
+ });
17
+ return { runtime, sessions, runEvents };
18
+ }
@@ -0,0 +1,35 @@
1
+ import assert from "node:assert/strict";
2
+ import { MockLanguageModelV4 } from "ai/test";
3
+ import { EngineRegistry } from "@vraxis/agent-v";
4
+ import { createBasicAiAgent } from "./basic-ai-sdk.ts";
5
+ import { createPublishContributionTool } from "./approved-tool.ts";
6
+ import { createLocalOllama } from "./ollama.ts";
7
+ import { createRepositorySummaryRequest } from "./local-cli.ts";
8
+ import { createStatefulRuntime } from "./sessions-and-events.ts";
9
+ import { createResolvedModelEngine } from "./custom-model-resolver.ts";
10
+ import { registerFilesystemSkill } from "./filesystem-skill.ts";
11
+
12
+ const usage = {
13
+ inputTokens: { total: 1, noCache: 1, cacheRead: undefined, cacheWrite: undefined },
14
+ outputTokens: { total: 1, text: 1, reasoning: undefined },
15
+ };
16
+ const model = new MockLanguageModelV4({
17
+ doGenerate: async () => ({
18
+ content: [{ type: "text", text: "example-ok" }],
19
+ finishReason: { unified: "stop", raw: undefined },
20
+ usage,
21
+ warnings: [],
22
+ }),
23
+ });
24
+
25
+ const basic = createBasicAiAgent(model);
26
+ const result = await basic.runtime.run(basic.agent, { scope: basic.scope, input: { prompt: "Verify the example." } });
27
+ assert.equal(result.text, "example-ok");
28
+
29
+ assert.equal(createPublishContributionTool(async () => ({ channelId: "devto" })).requiresApproval, true);
30
+ assert.equal(createLocalOllama("example-model").ollama.agent.descriptor.provider, "ollama");
31
+ assert.equal(createRepositorySummaryRequest(process.cwd()).request.workspaceAccess, "read-only");
32
+ assert.equal(createStatefulRuntime(basic.runtime.engines.require("primary-agent", "tool-agent")).sessions.constructor.name, "MemorySessionStore");
33
+ assert.equal(createResolvedModelEngine(() => model).descriptor.id, "profiled-agent");
34
+ assert.equal((await registerFilesystemSkill("skills/agent-v")).loaded.skill.id, "agent-v");
35
+ assert.equal(new EngineRegistry().list().length, 0);
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2023",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "noUncheckedIndexedAccess": true,
8
+ "verbatimModuleSyntax": true,
9
+ "isolatedModules": true,
10
+ "skipLibCheck": true,
11
+ "types": ["node"],
12
+ "allowImportingTsExtensions": true,
13
+ "noEmit": true
14
+ },
15
+ "include": ["./**/*.ts"]
16
+ }
package/llms.txt ADDED
@@ -0,0 +1,13 @@
1
+ # agent-v
2
+
3
+ > Provider-neutral TypeScript execution contracts for scoped agents, validated tools, approvals, AI SDK models, local coding runtimes, Ollama, sessions, events, and portable skills.
4
+
5
+ ## Canonical guidance
6
+
7
+ - README.md — supported consumer surface and installation
8
+ - ARCHITECTURE.md — dependency, authority, and product boundaries
9
+ - compatibility.json — machine-readable adapter strategies and dependency ranges
10
+ - skills/agent-v/SKILL.md — portable coding-agent integration instructions
11
+ - examples/ — compiled and executed consumer patterns
12
+
13
+ Do not infer APIs from other agent frameworks. Verify imports against the installed package exports and type declarations.
package/package.json ADDED
@@ -0,0 +1,97 @@
1
+ {
2
+ "name": "@vraxis/agent-v",
3
+ "version": "0.4.0",
4
+ "description": "A provider-neutral engine for building inspectable, extensible agentic products.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/Vequan23/agent-v.git"
8
+ },
9
+ "homepage": "https://github.com/Vequan23/agent-v#readme",
10
+ "bugs": "https://github.com/Vequan23/agent-v/issues",
11
+ "keywords": [
12
+ "agents",
13
+ "ai",
14
+ "tools",
15
+ "skills",
16
+ "local-first",
17
+ "typescript"
18
+ ],
19
+ "type": "module",
20
+ "sideEffects": false,
21
+ "license": "MIT",
22
+ "engines": {
23
+ "node": ">=22.12"
24
+ },
25
+ "bin": {
26
+ "agent-v": "dist/cli/index.js"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "README.md",
31
+ "ARCHITECTURE.md",
32
+ "CHANGELOG.md",
33
+ "AGENTS.md",
34
+ "compatibility.json",
35
+ "llms.txt",
36
+ "examples",
37
+ "skills",
38
+ "LICENSE"
39
+ ],
40
+ "exports": {
41
+ ".": {
42
+ "types": "./dist/core/index.d.ts",
43
+ "import": "./dist/core/index.js"
44
+ },
45
+ "./ai-sdk": {
46
+ "types": "./dist/adapters/ai-sdk/index.d.ts",
47
+ "import": "./dist/adapters/ai-sdk/index.js"
48
+ },
49
+ "./local-cli": {
50
+ "types": "./dist/adapters/local-cli/index.d.ts",
51
+ "import": "./dist/adapters/local-cli/index.js"
52
+ },
53
+ "./ollama": {
54
+ "types": "./dist/adapters/ollama/index.d.ts",
55
+ "import": "./dist/adapters/ollama/index.js"
56
+ },
57
+ "./node": {
58
+ "types": "./dist/node/index.d.ts",
59
+ "import": "./dist/node/index.js"
60
+ },
61
+ "./testing": {
62
+ "types": "./dist/testing/index.d.ts",
63
+ "import": "./dist/testing/index.js"
64
+ },
65
+ "./compatibility": "./compatibility.json"
66
+ },
67
+ "scripts": {
68
+ "build": "tsc -p tsconfig.build.json",
69
+ "typecheck": "tsc --noEmit -p tsconfig.json",
70
+ "test": "node --import tsx --test test/*.test.ts",
71
+ "test:examples": "tsc --noEmit -p examples/tsconfig.json && node --import tsx examples/smoke.ts",
72
+ "test:package": "node test/package-smoke.mjs",
73
+ "check": "npm run typecheck && npm test && npm run build && npm run test:examples && npm run test:package && npm pack --dry-run --cache .npm-cache"
74
+ },
75
+ "peerDependencies": {
76
+ "ai": ">=7.0.0 <8",
77
+ "ai-sdk-ollama": ">=4.2.0 <5"
78
+ },
79
+ "peerDependenciesMeta": {
80
+ "ai": {
81
+ "optional": true
82
+ },
83
+ "ai-sdk-ollama": {
84
+ "optional": true
85
+ }
86
+ },
87
+ "devDependencies": {
88
+ "@types/node": "^24.10.0",
89
+ "ai": "^7.0.79",
90
+ "ai-sdk-ollama": "^4.2.0",
91
+ "tsx": "^4.23.12",
92
+ "typescript": "^5.9.3"
93
+ },
94
+ "dependencies": {
95
+ "yaml": "^2.9.0"
96
+ }
97
+ }
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: agent-v
3
+ description: Integrate or extend the agent-v TypeScript library for scoped agents, tools, approvals, AI SDK models, local coding runtimes, Ollama, sessions, events, or Agent Skills.
4
+ metadata:
5
+ version: "0.4.0"
6
+ ---
7
+
8
+ # Use agent-v accurately
9
+
10
+ Read the installed package's `README.md` and type declarations before coding. Do not infer methods from other agent frameworks or older `agent-v` examples.
11
+
12
+ ## Route by execution need
13
+
14
+ - Use `@vraxis/agent-v` for contracts, scopes, agent blueprints, tool/skill definitions, registries, and policies.
15
+ - Use `@vraxis/agent-v/ai-sdk` for structured model calls and tool-loop agents backed by AI SDK 7.
16
+ - Use `@vraxis/agent-v/ollama` only for an Ollama model server. Inspect readiness before registration.
17
+ - Use `@vraxis/agent-v/local-cli` when Codex, OpenCode, Claude Code, or another coding CLI must operate on a workspace.
18
+ - Use `@vraxis/agent-v/node` for local sessions, run ledgers, diagnostics, and filesystem Agent Skills.
19
+ - Use `@vraxis/agent-v/testing` for deterministic tests without provider calls.
20
+
21
+ Do not substitute a coding CLI adapter for an ordinary model provider or treat Ollama as a coding-workspace runtime.
22
+
23
+ ## Preserve the execution contract
24
+
25
+ - Supply `ExecutionScope` on every run. Use `localExecutionScope()` only for genuinely single-user local applications.
26
+ - Declare every agent's skills, tools, and required capabilities explicitly.
27
+ - Give each tool stable input and output contracts, version, risk, side-effect classification, permissions, approval behavior, and timeout.
28
+ - Require approval for external side effects and privileged actions. Never weaken policy after a denial or adapter failure.
29
+ - Treat artifacts as host-supplied evidence. Keep product-specific evidence judgment, retrieval, prompts, and UX in the consuming product.
30
+ - Persist returned normalized events and provenance when runs must be auditable.
31
+ - Use readiness results and capability declarations rather than assuming an installed CLI or daemon is usable.
32
+
33
+ ## Implement and verify
34
+
35
+ Use the closest maintained example under `examples/` as the starting point. Read [references/integration-patterns.md](references/integration-patterns.md) for composition rules and common failure modes when creating or reviewing an integration.
36
+
37
+ Run the consuming project's typecheck and tests. In this repository, run `npm run check`; it compiles and executes all examples against the built package surface.
38
+
39
+ Do not make live provider calls, start daemons, download models, publish, or modify external systems unless the user authorized that action.
@@ -0,0 +1,57 @@
1
+ # Integration patterns
2
+
3
+ ## Contents
4
+
5
+ - Choosing an engine
6
+ - Defining tools safely
7
+ - Composing an agent
8
+ - Persistence and provenance
9
+ - Common mistakes
10
+
11
+ ## Choosing an engine
12
+
13
+ Choose from required behavior, not provider preference:
14
+
15
+ | Need | Import | Contract |
16
+ | --- | --- | --- |
17
+ | One schema-bound model operation | `@vraxis/agent-v/ai-sdk` | `StructuredModelEngine` |
18
+ | Bounded model/tool loop | `@vraxis/agent-v/ai-sdk` | `ToolAgentEngine` |
19
+ | Local or remote Ollama model | `@vraxis/agent-v/ollama` | AI SDK engines through `OllamaRuntime` |
20
+ | Coding agent against a workspace | `@vraxis/agent-v/local-cli` | `CodingRuntimeEngine` |
21
+ | Local persistence or diagnostics | `@vraxis/agent-v/node` | Store and doctor ports |
22
+
23
+ An executable being installed is not readiness evidence. Inspect first; use a bounded live probe only when its credentials, cost, and external effects are authorized.
24
+
25
+ ## Defining tools safely
26
+
27
+ Use `defineTool()` and provide all required authority metadata. `risk` describes impact; `sideEffect` describes replay behavior; `requiredPermissions` is checked against the current execution scope. `requiresApproval` is mandatory for `external-side-effect` and `privileged` risks.
28
+
29
+ Validate the tool's returned value with `output`. Tool implementation bugs must not become unvalidated model context.
30
+
31
+ Keep product-specific tools with their product until their contract and safety semantics are demonstrably reusable.
32
+
33
+ ## Composing an agent
34
+
35
+ Use `defineAgent()` with either `engineId` or `profileId`, never both. Profiles select deploy-time engine, model, credential reference, and provider options without changing the blueprint.
36
+
37
+ When skills are selected, their combined tool allowlist constrains the blueprint. A mismatch is an agent-definition error, not a reason to silently omit a tool.
38
+
39
+ Declare only capabilities the workflow actually needs. Selection should fail if the engine cannot enforce one.
40
+
41
+ ## Persistence and provenance
42
+
43
+ Sessions and event queries are isolated by tenant, project, principal, and optional engagement. Preserve that scope when replacing the reference stores.
44
+
45
+ Every `RunProvenance` has an `adapterStrategy`. Local CLI and Ollama runs also include the detected runtime version when available. Store provenance with outcomes so upstream changes can be correlated with regressions.
46
+
47
+ Configuration contains credential references. Resolve credential values inside the host's model resolver; never write values to config, events, sessions, examples, or fixtures.
48
+
49
+ ## Common mistakes
50
+
51
+ - Importing provider SDK types into product domain code instead of registering an adapter.
52
+ - Omitting `ExecutionScope` or granting wildcard permissions outside a local single-user application.
53
+ - Treating a skill's `allowed-tools` metadata as approval for side effects.
54
+ - Assuming OpenCode can enforce read-only access or Cursor can guarantee structured output when their current adapter capabilities say otherwise.
55
+ - Registering Ollama without checking that the daemon is reachable and the selected model is installed.
56
+ - Retrying malformed output by removing the schema requirement.
57
+ - Copying examples without compiling them against the installed package version.