create-relkit 0.0.5 → 0.1.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 (22) hide show
  1. package/dist/templates/default/README.md +1 -1
  2. package/dist/templates/default/v1/agent/package.json +4 -4
  3. package/dist/templates/default/v1/agent/src/hello/agents/assistant.agent.ts +8 -1
  4. package/dist/templates/default/v1/agent/src/hello/functions/ask-assistant.function.ts +16 -0
  5. package/dist/templates/default/v1/agent/src/hello/functions/hello.function.ts +3 -0
  6. package/dist/templates/default/v1/agent/src/hello/tools/lookup.tool.ts +2 -0
  7. package/dist/templates/default/v1/agent/tests/fixtures/lookup.tool.ts +12 -0
  8. package/dist/templates/default/v1/agent/tests/fixtures/mcp-options.ts +26 -0
  9. package/dist/templates/default/v1/agent/tests/unit/assistant.agent.test.ts +17 -4
  10. package/dist/templates/default/v1/agent/tests/unit/lookup.tool.test.ts +20 -0
  11. package/dist/templates/default/v1/api/package.json +5 -5
  12. package/dist/templates/default/v1/api/src/orders/events/order-created.event.ts +4 -1
  13. package/dist/templates/default/v1/api/src/orders/functions/create-order.function.ts +14 -4
  14. package/dist/templates/default/v1/api/src/orders/functions/order-audit.function.ts +15 -0
  15. package/dist/templates/default/v1/api/src/orders/functions/order-confirmation.function.ts +15 -0
  16. package/dist/templates/default/v1/api/tests/integration/order-events.test.ts +7 -15
  17. package/dist/templates/default/v1/api/tests/integration/orders.route.test.ts +1 -1
  18. package/dist/templates/default/v1/api/tests/unit/orders.function.test.ts +4 -2
  19. package/dist/templates/default/v1/minimal/package.json +4 -4
  20. package/package.json +1 -1
  21. package/dist/templates/default/v1/api/src/orders/events/order-audit.event.ts +0 -15
  22. package/dist/templates/default/v1/api/src/orders/events/order-confirmation.event.ts +0 -11
@@ -8,6 +8,6 @@ scaffolder:
8
8
  - `agent` — the minimal example plus a read-only tool and agent descriptor.
9
9
 
10
10
  Each variant is self-contained and can be copied as a project root. It uses
11
- the current checked-in RelKit package version (`0.0.5`), Bun `1.3.10`, and
11
+ the current checked-in RelKit package version (`0.1.0`), Bun `1.3.10`, and
12
12
  TypeScript `5.9.3`. The generator owns project-name substitution and later
13
13
  installation/Git behavior.
@@ -17,13 +17,13 @@
17
17
  "deploy": "relkit deploy up"
18
18
  },
19
19
  "dependencies": {
20
- "@relkit/app": "0.0.5",
21
- "@relkit/providers-standard": "0.0.5"
20
+ "@relkit/app": "0.1.0",
21
+ "@relkit/providers-standard": "0.1.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/bun": "1.3.10",
25
- "@relkit/cli": "0.0.5",
26
- "@relkit/testing": "0.0.5",
25
+ "@relkit/cli": "0.1.0",
26
+ "@relkit/testing": "0.1.0",
27
27
  "typescript": "5.9.3"
28
28
  }
29
29
  }
@@ -4,10 +4,17 @@ import lookup from "@app/hello/tools/lookup.tool.js";
4
4
 
5
5
  export default defineAgent({
6
6
  id: "hello.assistant",
7
+
7
8
  input: z.object({ question: z.string().min(1) }),
8
9
  output: z.object({ answer: z.string() }),
10
+
9
11
  model: "openai:gpt-5-mini",
10
12
  instructions: "Answer greeting questions with the read-only lookup tool.",
11
13
  tools: [lookup],
12
- limits: { maxSteps: 4, maxToolCalls: 4, timeoutMs: 10_000 },
14
+
15
+ limits: {
16
+ maxSteps: 4,
17
+ maxToolCalls: 4,
18
+ timeoutMs: 10_000,
19
+ },
13
20
  });
@@ -0,0 +1,16 @@
1
+ import { defineFunction } from "@relkit/app/functions";
2
+ import { z } from "@relkit/app/schema";
3
+ import assistant from "@app/hello/agents/assistant.agent.js";
4
+
5
+ export default defineFunction({
6
+ id: "hello.ask-assistant",
7
+
8
+ input: z.object({ question: z.string().min(1) }),
9
+ output: z.object({ answer: z.string() }),
10
+
11
+ dependencies: { agents: { assistant } },
12
+
13
+ handler: async (input, context) => {
14
+ return context.agents.assistant(input);
15
+ },
16
+ });
@@ -3,10 +3,13 @@ import { z } from "@relkit/app/schema";
3
3
 
4
4
  const hello = defineFunction({
5
5
  id: "hello.greet",
6
+
6
7
  input: z.object({ name: z.string().min(1).default("world") }),
7
8
  output: z.object({ message: z.string() }),
9
+
8
10
  handler: async ({ name }, context) => {
9
11
  context.log.info("hello invoked", { name });
12
+
10
13
  return { message: `Hello, ${name}!` };
11
14
  },
12
15
  });
@@ -3,6 +3,8 @@ import hello from "@app/hello/functions/hello.function.js";
3
3
  export default hello.asTool({
4
4
  id: "hello.lookup",
5
5
  description: "Read a greeting for a supplied name",
6
+
6
7
  sideEffect: "read",
7
8
  approval: "never",
9
+ timeoutMs: 2_000,
8
10
  });
@@ -0,0 +1,12 @@
1
+ import { defineTool } from "@relkit/app/tools";
2
+ import hello from "@app/hello/functions/hello.function.js";
3
+
4
+ export default defineTool({
5
+ id: "hello.lookup",
6
+ target: hello,
7
+ description: "Read a greeting for a supplied name",
8
+
9
+ sideEffect: "read",
10
+ approval: "never",
11
+ timeoutMs: 2_000,
12
+ });
@@ -0,0 +1,26 @@
1
+ // #region private-tool
2
+ import hello from "@app/hello/functions/hello.function.js";
3
+
4
+ export const privateLookup = hello.asTool({
5
+ id: "hello.private-lookup",
6
+ description: "Read a greeting inside this app only",
7
+
8
+ sideEffect: "read",
9
+ approval: "never",
10
+ timeoutMs: 2_000,
11
+ mcp: false,
12
+ });
13
+ // #endregion private-tool
14
+
15
+ import { defineConfig } from "@relkit/app/config";
16
+ import env from "@app/platform/env.js";
17
+
18
+ export const mcpDisabled = defineConfig({
19
+ env,
20
+ // #region disable-mcp
21
+ server: {
22
+ port: 3000,
23
+ mcp: false,
24
+ },
25
+ // #endregion disable-mcp
26
+ });
@@ -1,6 +1,7 @@
1
1
  import { expect, test } from "bun:test";
2
2
  import { createTestAgent, invokeFunction } from "@relkit/testing";
3
3
  import assistant from "@app/hello/agents/assistant.agent.js";
4
+ import askAssistant from "@app/hello/functions/ask-assistant.function.js";
4
5
  import hello from "@app/hello/functions/hello.function.js";
5
6
  import lookup from "@app/hello/tools/lookup.tool.js";
6
7
 
@@ -17,14 +18,26 @@ test("assistant uses a function-derived tool with an offline AI SDK model", asyn
17
18
  invokeFunction(hello, request.input as Parameters<typeof hello.invoke>[0]),
18
19
  },
19
20
  model: { provider: "openai", modelId: "gpt-5-mini" },
21
+ // Script the model's choices while running the real greeting function.
20
22
  script: [
21
- { type: "tool-call", callId: "call-1", toolId: "hello.lookup", input: { name: "Ada" } },
23
+ {
24
+ type: "tool-call",
25
+ callId: "call-1",
26
+ toolId: "hello.lookup",
27
+ input: { name: "Ada" },
28
+ },
22
29
  { type: "final", output: { answer: "Hello, Ada!" } },
23
30
  ],
24
31
  });
25
32
 
26
- await expect(agent.invoke({ question: "greet Ada" })).resolves.toEqual({
27
- answer: "Hello, Ada!",
28
- });
33
+ await expect(
34
+ invokeFunction(
35
+ askAssistant,
36
+ { question: "greet Ada" },
37
+ {
38
+ clients: { agents: { "hello.assistant": agent.invoke } },
39
+ },
40
+ ),
41
+ ).resolves.toEqual({ answer: "Hello, Ada!" });
29
42
  expect(agent.model.calls).toHaveLength(2);
30
43
  });
@@ -0,0 +1,20 @@
1
+ import { expect, test } from "bun:test";
2
+ import hello from "@app/hello/functions/hello.function.js";
3
+ import lookup from "../fixtures/lookup.tool.js";
4
+ import { mcpDisabled, privateLookup } from "../fixtures/mcp-options.js";
5
+
6
+ test("defineTool reuses the greeting function", async () => {
7
+ expect(lookup.target.ref).toEqual(hello.ref);
8
+ expect(lookup.mcp).toBe(true);
9
+ await expect(lookup.invoke({ name: "Ada" })).resolves.toEqual({
10
+ message: "Hello, Ada!",
11
+ });
12
+ });
13
+
14
+ test("MCP visibility can be disabled without disabling ordinary tool invocation", async () => {
15
+ expect(privateLookup.mcp).toBe(false);
16
+ expect(mcpDisabled.server?.mcp).toBe(false);
17
+ await expect(privateLookup.invoke({ name: "Ada" })).resolves.toEqual({
18
+ message: "Hello, Ada!",
19
+ });
20
+ });
@@ -17,14 +17,14 @@
17
17
  "deploy": "relkit deploy up"
18
18
  },
19
19
  "dependencies": {
20
- "@relkit/app": "0.0.5",
21
- "@relkit/providers-standard": "0.0.5"
20
+ "@relkit/app": "0.1.0",
21
+ "@relkit/providers-standard": "0.1.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/bun": "1.3.10",
25
- "@relkit/cli": "0.0.5",
26
- "@relkit/events": "0.0.5",
27
- "@relkit/testing": "0.0.5",
25
+ "@relkit/cli": "0.1.0",
26
+ "@relkit/events": "0.1.0",
27
+ "@relkit/testing": "0.1.0",
28
28
  "typescript": "5.9.3"
29
29
  }
30
30
  }
@@ -4,11 +4,14 @@ import { z } from "@relkit/app/schema";
4
4
  const orderCreated = defineEvent({
5
5
  id: "orders.created",
6
6
  version: 1,
7
- payload: z.object({
7
+
8
+ // Data every subscriber receives when an order is created.
9
+ input: z.object({
8
10
  orderId: z.string().min(1),
9
11
  sku: z.string().min(1),
10
12
  totalCents: z.number().int().nonnegative(),
11
13
  }),
14
+
12
15
  title: "Order created",
13
16
  });
14
17
 
@@ -1,6 +1,5 @@
1
1
  import { defineFunction } from "@relkit/app/functions";
2
2
  import { z } from "@relkit/app/schema";
3
- import orderCreated from "@app/orders/events/order-created.event.js";
4
3
  import priceOrder from "@app/orders/functions/price-order.function.js";
5
4
 
6
5
  const orderInput = z.object({
@@ -8,6 +7,7 @@ const orderInput = z.object({
8
7
  sku: z.string().min(1),
9
8
  quantity: z.number().int().positive(),
10
9
  });
10
+
11
11
  const orderOutput = z.object({
12
12
  orderId: z.string(),
13
13
  sku: z.string(),
@@ -17,11 +17,21 @@ const orderOutput = z.object({
17
17
  const createOrder = defineFunction({
18
18
  input: orderInput,
19
19
  output: orderOutput,
20
- dependencies: { events: { orderCreated } },
20
+
21
+ // Events this function is allowed to publish.
22
+ publishes: ["orders.created"],
23
+
21
24
  handler: async (input, context) => {
22
25
  const { totalCents } = await priceOrder.invoke({ quantity: input.quantity });
23
- const order = { orderId: input.orderId, sku: input.sku, totalCents };
24
- await context.events.orderCreated.publish(order);
26
+ const order = {
27
+ orderId: input.orderId,
28
+ sku: input.sku,
29
+ totalCents,
30
+ };
31
+
32
+ // Let subscribers react to the new order.
33
+ await context.events["orders.created"].publish(order);
34
+
25
35
  return order;
26
36
  },
27
37
  });
@@ -0,0 +1,15 @@
1
+ import { defineEventFunction } from "@relkit/app/events";
2
+
3
+ const orderAudit = defineEventFunction({
4
+ id: "orders.audit",
5
+ event: "orders.created",
6
+ handler: async (payload, context) => {
7
+ context.log.info("order.audit.recorded", {
8
+ orderId: payload.orderId,
9
+ sku: payload.sku,
10
+ totalCents: payload.totalCents,
11
+ });
12
+ },
13
+ });
14
+
15
+ export default orderAudit;
@@ -0,0 +1,15 @@
1
+ import { defineEventFunction } from "@relkit/app/events";
2
+
3
+ const orderConfirmation = defineEventFunction({
4
+ id: "orders.confirmation",
5
+ event: "orders.created",
6
+
7
+ handler: async (payload, context) => {
8
+ // Replace this log with your email-sending code.
9
+ context.log.info("order.confirmation.requested", {
10
+ orderId: payload.orderId,
11
+ });
12
+ },
13
+ });
14
+
15
+ export default orderConfirmation;
@@ -1,9 +1,9 @@
1
1
  import { expect, test } from "bun:test";
2
- import { createEventListenerTarget, eventListenerFunctionId } from "@relkit/app/events";
2
+ import { bindFunctionEvents } from "@relkit/app/events";
3
3
  import { createTestEvent, invokeFunction } from "@relkit/testing";
4
4
  import orderCreated from "@app/orders/events/order-created.event.js";
5
- import orderAudit from "@app/orders/events/order-audit.event.js";
6
- import orderConfirmation from "@app/orders/events/order-confirmation.event.js";
5
+ import orderAudit from "@app/orders/functions/order-audit.function.js";
6
+ import orderConfirmation from "@app/orders/functions/order-confirmation.function.js";
7
7
  import orders from "@app/orders/service.js";
8
8
 
9
9
  const retry = {
@@ -15,16 +15,8 @@ const retry = {
15
15
  };
16
16
 
17
17
  test("order.created fans out deterministic independent deliveries", async () => {
18
- const confirmationTarget = createEventListenerTarget(
19
- orderConfirmation,
20
- [orderCreated],
21
- eventListenerFunctionId(orderConfirmation.id),
22
- );
23
- const auditTarget = createEventListenerTarget(
24
- orderAudit,
25
- [orderCreated],
26
- eventListenerFunctionId(orderAudit.id),
27
- );
18
+ const confirmationTarget = orderConfirmation;
19
+ const auditTarget = orderAudit;
28
20
  const failingAuditTarget = {
29
21
  ...auditTarget,
30
22
  handler: async (...args: Parameters<typeof auditTarget.handler>) => {
@@ -43,9 +35,9 @@ test("order.created fans out deterministic independent deliveries", async () =>
43
35
  try {
44
36
  await expect(
45
37
  invokeFunction(
46
- orders.createOrder,
38
+ bindFunctionEvents(orders.createOrder, undefined, [orderCreated]),
47
39
  { orderId: "order-1", sku: "book", quantity: 3 },
48
- { clients: { events: { orderCreated: event.provider } } },
40
+ { clients: { events: { "orders.created": event.provider } } },
49
41
  ),
50
42
  ).resolves.toEqual({ orderId: "order-1", sku: "book", totalCents: 300 });
51
43
 
@@ -3,7 +3,7 @@ import { createTestApplication } from "@relkit/testing";
3
3
  import config from "../../relkit.config.js";
4
4
 
5
5
  const testApp = await createTestApplication(config);
6
- testApp.fakes.setClient("events", "orderCreated", {
6
+ testApp.fakes.setClient("events", "orders.created", {
7
7
  publish: async () => ({ accepted: true, instanceId: "event-1" }),
8
8
  });
9
9
 
@@ -1,16 +1,18 @@
1
1
  import { expect, test } from "bun:test";
2
2
  import { invokeFunction } from "@relkit/testing";
3
3
  import orders from "@app/orders/service.js";
4
+ import { bindFunctionEvents } from "@relkit/app/events";
5
+ import orderCreated from "@app/orders/events/order-created.event.js";
4
6
 
5
7
  test("createOrder invokes pricing and publishes the order event", async () => {
6
8
  const published: unknown[] = [];
7
9
  const result = await invokeFunction(
8
- orders.createOrder,
10
+ bindFunctionEvents(orders.createOrder, undefined, [orderCreated]),
9
11
  { orderId: "order-1", sku: "book", quantity: 3 },
10
12
  {
11
13
  clients: {
12
14
  events: {
13
- orderCreated: {
15
+ "orders.created": {
14
16
  publish: async (payload: unknown) => {
15
17
  published.push(payload);
16
18
  return { accepted: true, instanceId: "event-1" };
@@ -17,13 +17,13 @@
17
17
  "deploy": "relkit deploy up"
18
18
  },
19
19
  "dependencies": {
20
- "@relkit/app": "0.0.5",
21
- "@relkit/providers-standard": "0.0.5"
20
+ "@relkit/app": "0.1.0",
21
+ "@relkit/providers-standard": "0.1.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/bun": "1.3.10",
25
- "@relkit/cli": "0.0.5",
26
- "@relkit/testing": "0.0.5",
25
+ "@relkit/cli": "0.1.0",
26
+ "@relkit/testing": "0.1.0",
27
27
  "typescript": "5.9.3"
28
28
  }
29
29
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-relkit",
3
- "version": "0.0.5",
3
+ "version": "0.1.0",
4
4
  "description": "Create a RELKIT application from a supported project template.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,15 +0,0 @@
1
- import { onEvent } from "@relkit/app/events";
2
-
3
- const orderAudit = onEvent(
4
- "orders.created",
5
- async (payload, context) => {
6
- context.log.info("order.audit.recorded", {
7
- orderId: payload.orderId,
8
- sku: payload.sku,
9
- totalCents: payload.totalCents,
10
- });
11
- },
12
- { id: "orders.audit" },
13
- );
14
-
15
- export default orderAudit;
@@ -1,11 +0,0 @@
1
- import { onEvent } from "@relkit/app/events";
2
-
3
- const orderConfirmation = onEvent(
4
- "orders.created",
5
- async (payload, context) => {
6
- context.log.info("order.confirmation.requested", { orderId: payload.orderId });
7
- },
8
- { id: "orders.confirmation" },
9
- );
10
-
11
- export default orderConfirmation;