@kazzle/app 0.1.726 → 0.1.727

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -12,6 +12,9 @@
12
12
  // app via the injected `KAZZLE_APP_COMPONENT_<NAME>_URL` env var. That URL
13
13
  // is server-to-server only — never expose it to the browser.
14
14
  //
15
+ // For thread vs Tools API branching, read `Kazzle-Tool-Context` via
16
+ // `toolContext(req)` from `@kazzle/app/tools` (not this module).
17
+ //
15
18
  // Dependency-free on purpose (uses global fetch). Do not add zod/vite here.
16
19
  /** Read the injected base URL of the Kazzle API for install-secret calls. */
17
20
  export function kazzleApiUrl() {
package/dist/tools.d.ts CHANGED
@@ -1,4 +1,26 @@
1
1
  import type { z } from 'zod';
2
+ /** Header Kazzle sets on every dispatched app-tool HTTP request. Source of truth: shared/tools/tool-invocation.types.ts */
3
+ export declare const TOOL_CONTEXT_HEADER = "Kazzle-Tool-Context";
4
+ export declare const ToolInvocationSource: {
5
+ readonly THREAD: "thread";
6
+ readonly API: "api";
7
+ };
8
+ export type ToolInvocationSource = typeof ToolInvocationSource[keyof typeof ToolInvocationSource];
9
+ /** How this tool call was invoked — thread (AI / resume) vs Tools API. */
10
+ export type ToolInvocationContext = {
11
+ source: typeof ToolInvocationSource.THREAD;
12
+ threadId: string;
13
+ } | {
14
+ source: typeof ToolInvocationSource.API;
15
+ };
16
+ /**
17
+ * Read `Kazzle-Tool-Context` from an incoming tool handler request.
18
+ * Throws when the header is missing or malformed — only Kazzle dispatch should call the route.
19
+ */
20
+ export declare function toolContext(req: Request): ToolInvocationContext;
21
+ export declare function isThreadToolInvocation(context: ToolInvocationContext): context is Extract<ToolInvocationContext, {
22
+ source: typeof ToolInvocationSource.THREAD;
23
+ }>;
2
24
  /** Zod schema for a tool's input object. Use .default(), .optional(), .transform(), etc. */
3
25
  export type KazzleToolInputSchema = z.ZodType<Record<string, unknown>>;
4
26
  export type ToolRequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
@@ -19,7 +41,7 @@ export type KazzleTarget = ({
19
41
  type: 'kazzle';
20
42
  name: string;
21
43
  };
22
- export interface ToolInputButtonElement {
44
+ export interface ToolActionButtonElement {
23
45
  type: 'button';
24
46
  id: string;
25
47
  label: string;
@@ -34,21 +56,27 @@ export interface ToolInputButtonElement {
34
56
  variant?: 'primary' | 'secondary' | 'destructive';
35
57
  }
36
58
  /**
37
- * A pending-input card element. Only buttons are rendered today; this stays a
59
+ * A required-action card element. Only buttons are rendered today; this stays a
38
60
  * union so form controls can be added later alongside their renderer.
39
61
  */
40
- export type ToolInputElement = ToolInputButtonElement;
41
- export interface KazzlePendingInput {
42
- type: 'pending_input';
62
+ export type ToolActionElement = ToolActionButtonElement;
63
+ export interface ToolActionAssignee {
64
+ computerId?: string;
65
+ userId?: string;
66
+ }
67
+ export interface ToolActionSpec {
43
68
  title: string;
44
69
  description?: string;
45
- elements: ToolInputElement[];
46
- /**
47
- * Optional card lifetime in milliseconds. When set, the framework stamps an
48
- * absolute expiry, shows a countdown, and auto-presses the default-negative
49
- * (Skip) on the client OR headlessly on the server if no client is connected.
50
- * Omit for a card that waits indefinitely (its default negative reads Cancel).
51
- */
70
+ elements: ToolActionElement[];
71
+ assignee?: ToolActionAssignee;
72
+ timeoutMs?: number;
73
+ }
74
+ export interface KazzleRequiredAction {
75
+ type: 'action_required';
76
+ title: string;
77
+ description?: string;
78
+ elements: ToolActionElement[];
79
+ assignee?: ToolActionAssignee;
52
80
  timeoutMs?: number;
53
81
  }
54
82
  interface KazzleToolBase {
package/dist/tools.js CHANGED
@@ -16,6 +16,54 @@
16
16
  // server/apps/apps.skills.tools.ts — it reads the SAME shape defined here
17
17
  // (`name`, `displayName`, `description`, `input`, `target`).
18
18
  // If you change this contract, update that compiler and its tests together.
19
+ //
20
+ // Tool handlers (POST /tools/...) receive:
21
+ // - `Authorization: Bearer <install identity>` — scope secrets via KazzleInstallClient
22
+ // - `Kazzle-Tool-Context: <json>` — thread vs Tools API (`toolContext(req)`)
23
+ // Handlers may return plain text, `{ content }`, or `{ type: "action_required", ... }`
24
+ // to pause the thread until the user acts (see documents/tool-required-action.md).
25
+ // Set `assignee.computerId` when only a specific device may fulfill the card.
26
+ /** Header Kazzle sets on every dispatched app-tool HTTP request. Source of truth: shared/tools/tool-invocation.types.ts */
27
+ export const TOOL_CONTEXT_HEADER = 'Kazzle-Tool-Context';
28
+ export const ToolInvocationSource = {
29
+ THREAD: 'thread',
30
+ API: 'api',
31
+ };
32
+ /**
33
+ * Read `Kazzle-Tool-Context` from an incoming tool handler request.
34
+ * Throws when the header is missing or malformed — only Kazzle dispatch should call the route.
35
+ */
36
+ export function toolContext(req) {
37
+ const raw = req.headers.get(TOOL_CONTEXT_HEADER);
38
+ if (!raw) {
39
+ throw new Error(`Missing ${TOOL_CONTEXT_HEADER} header — expected a Kazzle tool dispatch.`);
40
+ }
41
+ let parsed;
42
+ try {
43
+ parsed = JSON.parse(raw);
44
+ }
45
+ catch {
46
+ throw new Error(`${TOOL_CONTEXT_HEADER} must be valid JSON.`);
47
+ }
48
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
49
+ throw new Error(`${TOOL_CONTEXT_HEADER} must be a JSON object.`);
50
+ }
51
+ const source = parsed.source;
52
+ if (source === ToolInvocationSource.API) {
53
+ return { source: ToolInvocationSource.API };
54
+ }
55
+ if (source === ToolInvocationSource.THREAD) {
56
+ const threadId = parsed.threadId;
57
+ if (typeof threadId !== 'string' || !threadId) {
58
+ throw new Error(`${TOOL_CONTEXT_HEADER} thread invocation requires threadId.`);
59
+ }
60
+ return { source: ToolInvocationSource.THREAD, threadId };
61
+ }
62
+ throw new Error(`${TOOL_CONTEXT_HEADER} source must be "thread" or "api".`);
63
+ }
64
+ export function isThreadToolInvocation(context) {
65
+ return context.source === ToolInvocationSource.THREAD;
66
+ }
19
67
  /** Type-safe tools helper. Use: export const tools = defineTools([...]) */
20
68
  export function defineTools(tools) {
21
69
  return tools;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kazzle/app",
3
- "version": "0.1.726",
3
+ "version": "0.1.727",
4
4
  "description": "Contracts, tool helpers, Vite helper, and templates for building Kazzle apps.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -35,7 +35,7 @@ import type { Context } from 'hono';
35
35
  import { cors } from 'hono/cors';
36
36
 
37
37
  const apiKey = process.env.KAZZLE_API_KEY;
38
- if (!apiKey) throw new Error('KAZZLE_API_KEY is required (mint with `api_key { action: "create" }`)');
38
+ if (!apiKey) throw new Error('KAZZLE_API_KEY is required (mint with `api_key { create: {} }`)');
39
39
  const apiUrl = process.env.KAZZLE_API_URL;
40
40
  if (!apiUrl) throw new Error('KAZZLE_API_URL is required and must point at the matching Kazzle API environment');
41
41
 
@@ -1,3 +1,6 @@
1
+ // Tool handlers receive Kazzle-Tool-Context — read with toolContext(req) from
2
+ // @kazzle/app/tools. Return { type: 'action_required', ... } only for thread
3
+ // calls; from the Tools API return a normal domain error. See documents/apps.md.
1
4
  import { z } from 'zod';
2
5
  import type { KazzleTool } from '@kazzle/app/tools';
3
6