{"_id":"@ajentify/sdk","name":"@ajentify/sdk","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@ajentify/sdk","version":"0.1.0","description":"Official TypeScript SDK for the Ajentify API. A clean, uniform wrapper over agents, contexts, tools, structured responses, data windows, API keys, JSON documents and models with Zod-first schemas.","type":"module","license":"MIT","author":{"name":"Ajentify"},"homepage":"https://ajentify.com","repository":{"type":"git","url":"git+https://github.com/ajentify/ajentify-sdk.git"},"publishConfig":{"access":"public"},"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"engines":{"node":">=18"},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"optionalDependencies":{"zod-to-json-schema":"^3.24.1"},"peerDependencies":{"zod":"^3.22.0 || ^4.0.0"},"peerDependenciesMeta":{"zod":{"optional":true}},"devDependencies":{"@types/node":"^22.10.5","tsup":"^8.3.5","typescript":"^5.7.3","vitest":"^2.1.8","zod":"^4.0.0","zod-to-json-schema":"^3.24.1"},"keywords":["ajentify","ai","agents","sdk","llm","tools","structured-output"],"_id":"@ajentify/sdk@0.1.0","gitHead":"c9fb21827eeaf043274f8986115bff334ea82e9b","bugs":{"url":"https://github.com/ajentify/ajentify-sdk/issues"},"_nodeVersion":"23.3.0","_npmVersion":"10.9.0","dist":{"integrity":"sha512-itSdrGm5Sh3Sa9n70Cpb3HKqLzExeNH5z9Ps8/sciFIVChcs1B10elvC2qX96DOl7PyMChT+CPEPC3uq2nq5ag==","shasum":"d8dae2a3d856ad7c35506a557ebd420f5e553542","tarball":"https://registry.npmjs.org/@ajentify/sdk/-/sdk-0.1.0.tgz","fileCount":9,"unpackedSize":352117,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDG9b79XcYAV4U8UD4/vFwSSqpT9LsV7TdjgaBdP5Oq0wIhANnIvmWMNLZwQk3hWXxB9R/ZFZgynRzB+CioopFQUXQu"}]},"_npmUser":{"name":"ajentify","email":"purpledevilai@gmail.com"},"directories":{},"maintainers":[{"name":"ajentify","email":"purpledevilai@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.1.0_1785442936776_0.7612360904474766"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-30T20:22:16.543Z","0.1.0":"2026-07-30T20:22:16.933Z","modified":"2026-07-30T20:22:17.197Z"},"maintainers":[{"name":"ajentify","email":"purpledevilai@gmail.com"}],"description":"Official TypeScript SDK for the Ajentify API. A clean, uniform wrapper over agents, contexts, tools, structured responses, data windows, API keys, JSON documents and models with Zod-first schemas.","homepage":"https://ajentify.com","keywords":["ajentify","ai","agents","sdk","llm","tools","structured-output"],"repository":{"type":"git","url":"git+https://github.com/ajentify/ajentify-sdk.git"},"author":{"name":"Ajentify"},"bugs":{"url":"https://github.com/ajentify/ajentify-sdk/issues"},"license":"MIT","readme":"# @ajentify/sdk\n\nThe official TypeScript SDK for the [Ajentify](https://ajentify.com) API. A clean, uniform wrapper over every Ajentify primitive — agents, contexts, tools, structured responses, data windows, API keys, JSON documents, and models — with Zod-first schemas and no `ParameterDefinition` / stage plumbing in sight.\n\n```ts\nimport { Agent, Context } from \"@ajentify/sdk\";\n\n// A message arrives (email, webhook, ...). Identify the sender, get or create\n// their context for a specific agent, then add their message and invoke.\nconst agent = await Agent.get(AGENT_ID);\nconst context =\n  (await lookupContextForUser(user)) ??\n  (await Context.create(agent.id, { userDefined: { accessToken } }));\n\nconst response = await context.addMessageAndInvoke(userMessage, {\n  clientSideTools: {\n    // client-side tool code resolves here, at invoke time\n    lookupPatient: async ({ mrn }) => db.find(mrn),\n  },\n});\n\nconsole.log(response.text);\n```\n\n## Install\n\n```bash\nnpm install @ajentify/sdk\n# Zod is an optional peer dependency — install it to author schemas:\nnpm install zod\n```\n\nRequires Node 18+ (uses the global `fetch`).\n\n## Authentication\n\nThe SDK reads your org API key from `AJENTIFY_API_KEY` by default (OpenAI-style). You can also configure it explicitly:\n\n```ts\nimport { configure, createClient } from \"@ajentify/sdk\";\n\n// Set global defaults used by the top-level namespaces.\nconfigure({ apiKey: \"aj_...\", baseUrl: \"https://api.ajentify.com\" });\n\n// Or create an isolated, per-key client (multi-tenant) exposing the same namespaces.\nconst aj = createClient({ apiKey: \"aj_...\" });\nconst agent = await aj.Agent.get(AGENT_ID);\n```\n\n> Client-type keys are for WebSocket/voice only and are rejected on the REST API — use an **org** key.\n\n## Design principles\n\n- **Uniform.** Every primitive follows `Primitive.create(...) -> instance`, with `get` / `list` / `update` / `delete`.\n- **ID-pointer rule.** References between resources are always IDs: `Agent.create(name, prompt, toolIds)`, `Context.create(agentId, ...)`, `terminating.toolIds`. Every returned instance has an `.id`.\n- **Zod-first schemas.** Anywhere a schema is needed, pass a Zod schema (types are inferred) or a raw JSON Schema object. `ParameterDefinition`s are managed for you.\n- **CRUD is secondary.** You *can* create resources from the SDK, but most are authored in the dashboard or deployed via stages.\n\n## Tools\n\n```ts\nimport { Tools } from \"@ajentify/sdk\";\nimport { z } from \"zod\";\n\n// Client-side tool: no code stored — its handler is supplied at invoke time.\nconst lookupPatient = await Tools.create(\"lookupPatient\", z.object({ mrn: z.string() }), {\n  isClientSide: true,\n  passContext: true,\n});\n\n// Server-side tool: Python code runs in Ajentify's sandbox.\nconst addNumbers = await Tools.create(\"addNumbers\", z.object({ a: z.number(), b: z.number() }), {\n  code: \"def add_numbers(a, b):\\n    return a + b\",\n});\n\nawait Tools.list();\nawait Tools.defaults(); // built-in platform tools\n```\n\n## Agents\n\n```ts\nimport { Agent } from \"@ajentify/sdk\";\n\nconst assistant = await Agent.create(\"Clinical Assistant\", systemPrompt, [lookupPatient.id], {\n  description: \"Helps clinicians look up patients\",\n  modelId: \"gpt-4o\",\n});\n```\n\n## Contexts & chat\n\nThe context is where most of the action lives.\n\n```ts\nconst context = await Context.create(assistant.id, { userDefined: { accessToken } });\n\n// Add a human message and invoke (save defaults to true).\nconst res = await context.addMessageAndInvoke(\"Look up patient 12345\", {\n  clientSideTools: { lookupPatient: async ({ mrn }, ctx) => db.find(mrn, ctx.userDefined) },\n});\n\n// Other message-stack controls:\nawait context.invoke();                 // invoke on the current stack\nawait context.addAiMessage(\"Noted.\");   // insert an AI message\nawait context.setMessages([...]);       // replace the whole stack\nawait context.refresh();                // re-fetch messages\n```\n\n### Client-side tool loop\n\nWhen you pass `clientSideTools`, the SDK runs the matching handlers and continues the conversation automatically until a final answer. Use `exitOn` to make specific tools break out of the loop and hand control back to you:\n\n```ts\nconst res = await context.addMessageAndInvoke(text, {\n  clientSideTools: { needsApproval: async () => \"\" },\n  exitOn: [\"needsApproval\"], // stops the loop; res.clientSideToolCalls is populated\n});\n\nif (res.needsClientSideTools) {\n  for (const call of res.clientSideToolCalls) {\n    // handle call.toolName / call.toolInput yourself, then:\n  }\n  await context.submitToolResponses([{ toolCallId: \"…\", response: \"…\" }]);\n}\n```\n\n### Approval workflow (generate now, save later)\n\n`InvokeResponse` is a pure data object. Persist `generatedMessages` wherever you like; on approval, reload the context and add them.\n\n```ts\n// 1. Generate WITHOUT saving to the context.\nconst draft = await context.addMessageAndInvoke(userMessage, { save: false });\n\n// 2. Persist the draft (in memory or your DB) and run human-in-the-loop review.\nawait db.saveDraft(contextId, draft.generatedMessages);\n\n// 3. On approval, reload the context and commit exactly those messages.\nconst ctx = await Context.get(contextId);\nawait ctx.addMessages(await db.loadDraft(contextId));\n```\n\n### Async responses (callback URL)\n\nAgent invocations can exceed API Gateway's 30s timeout. Pass a `callbackUrl` to dispatch asynchronously — the call returns an `AsyncAck` immediately, and the result is POSTed to your URL when finished.\n\nThe callback boundary is deliberately **stateless**: once the callback fires, no in-memory SDK state carries over. Encode whatever you need to resume — most importantly the context id — into the callback URL, then reload it in your handler and continue.\n\n```ts\n// Encode the context id (and anything else) into the callback URL.\nconst ack = await context.addMessageAndInvoke(userMessage, {\n  callbackUrl: `https://myapp.com/ajentify/callback?contextId=${context.id}`,\n  callbackToken: process.env.MY_WEBHOOK_SECRET, // sent as Authorization on the callback\n});\n// -> { status: \"processing\", requestId }\n```\n\n```ts\n// Later, in your webhook handler:\nimport { parseCallback, Context } from \"@ajentify/sdk\";\n\nconst { ok, response, error } = parseCallback(req.body);\nif (ok) {\n  // Reload state from the URL params you encoded — nothing is retained locally.\n  const contextId = new URL(req.url, \"https://myapp.com\").searchParams.get(\"contextId\")!;\n  const ctx = await Context.get(contextId);\n\n  // `response` is the raw endpoint payload. Type it if you like:\n  //   const { response: text } = parseCallback<{ response: string }>(req.body);\n  await sendReply((response as { response: string }).response);\n}\n```\n\nBecause the callback resolves in a separate process, the auto client-side tool loop does not run for it — the raw payload may include `client_side_tool_calls` for you to handle after reloading the context (run them, then `ctx.submitToolResponses(...)`).\n\n## Structured responses\n\n```ts\nimport { StructuredResponse } from \"@ajentify/sdk\";\nimport { z } from \"zod\";\n\n// Saved endpoint (reusable):\nconst sentiment = await StructuredResponse.create(\"sentiment\", {\n  schema: z.object({ sentiment: z.enum([\"positive\", \"negative\", \"neutral\"]) }),\n  promptTemplate: \"Classify the sentiment of: ${TEXT}\",\n  variableNames: [\"TEXT\"],\n});\nconst result = await sentiment.run({ TEXT: \"I love it!\" });\nresult.sentiment; // typed\n\n// One-shot inline:\nconst { answer } = await StructuredResponse.run({\n  prompt: \"What is 6 x 7?\",\n  schema: z.object({ answer: z.number() }),\n});\n```\n\n## Other resources\n\n```ts\nimport { DataWindow, ApiKey, JsonDocument, Models } from \"@ajentify/sdk\";\n\nawait DataWindow.create(\"kb\", \"knowledge base text\");\n\nconst key = await ApiKey.generate();      // key.token is returned once\nawait ApiKey.list();\n\nconst doc = await JsonDocument.create(\"config\", { featureFlags: {} });\nawait doc.setValue(\"featureFlags.beta\", true);\nawait doc.getValue(\"featureFlags.beta\");\n\nconst models = await Models.list();       // available LLMs + pricing\n```\n\n## Errors\n\nEvery failure surfaces as an `AjentifyError` with `status`, `code`, and `body` when the error came from the API.\n\n```ts\nimport { AjentifyError } from \"@ajentify/sdk\";\n\ntry {\n  await Agent.get(\"nope\");\n} catch (err) {\n  if (err instanceof AjentifyError) console.error(err.status, err.message);\n}\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-c57e6f9990161dc47b1e0d64b379be32"}