@trayai/helix-sdk 1.8.0 → 1.13.1

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 CHANGED
@@ -8,6 +8,37 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
  The SDK and [`@trayai/helix-cli`](https://www.npmjs.com/package/@trayai/helix-cli) are
9
9
  released together and share a version — install matching versions.
10
10
 
11
+ ## 1.13.1
12
+
13
+ ### Changed
14
+
15
+ - Documented the 15-minute handler time limit for scheduled functions and
16
+ `ctx.callFunctionAsync` targets (previously documented as 180 seconds), and that a failed
17
+ run is retried about a minute later rather than five.
18
+
19
+ ## 1.9.0
20
+
21
+ ### Added
22
+
23
+ - **Agents and tools are now a documented, public part of the SDK.** Define a tool with
24
+ `defineTool` (`functions/_tools/`) and an agent with `defineAgent` (`functions/_agents/`),
25
+ then run it from any handler with `ctx.agent(name).generate()` / `.stream()`. An agent's
26
+ `model`/`auth` use the same `aiProviders` aliases as `ctx.ai` (every provider, including
27
+ Amazon Bedrock), can declare `fallbacks`, and can delegate to other agents. Conversations
28
+ persist as **sessions** (the full record, not just the model window) — read them with
29
+ `session(id).messages()` / `.page()` and clear them with `session(id).clear()`; cap the model
30
+ window with `memory.maxSessionMessages`, scope sessions per user with `memory.scope: 'user'`.
31
+ Choose a session store with the new `agentSessions` field in `helix.config.ts`
32
+ (`{ store: 'managed' }` by default, or a bring-your-own `{ store: 'dynamodb', … }`). See the
33
+ README's "Agents and tools" section; try them locally with `helix agent list` / `helix agent
34
+ chat`. (These APIs shipped earlier marked beta; the beta label has been removed.)
35
+
36
+ ### Changed
37
+
38
+ - Removed the `@beta` labels from `defineAgent`, `defineTool`, `ctx.agent`, `HelixAgent`, and
39
+ `AgentClient` — the agent harness is now covered by the SDK's semantic-versioning contract
40
+ like the rest of the public API.
41
+
11
42
  ## 1.8.0
12
43
 
13
44
  ### Added
package/README.md CHANGED
@@ -15,6 +15,7 @@ The runtime SDK for **Helix** — a TypeScript-first platform for building integ
15
15
  - [Scheduled functions](#scheduled-functions)
16
16
  - [Async function calls](#async-function-calls)
17
17
  - [AI — `ctx.ai`](#ai--ctxai)
18
+ - [Agents and tools — `ctx.agent`](#agents-and-tools--ctxagent)
18
19
  - [Authentication](#authentication)
19
20
  - [Configuration](#configuration)
20
21
  - [Logging](#logging)
@@ -83,6 +84,7 @@ Every HTTP handler receives a `ctx` (`TrayContext`); scheduled handlers receive
83
84
  | `ctx.kv()` | Key-value store |
84
85
  | `ctx.files()` | File storage |
85
86
  | `ctx.ai(alias)` | AI provider access — credentials are injected by the platform, same as `ctx.http.authed` |
87
+ | `ctx.agent(name)` | Run an agent defined with `defineAgent` — `generate`/`stream`, with persisted conversation sessions |
86
88
  | `ctx.log.info/warn/error/debug` | Structured logging |
87
89
  | `ctx.config` | The `config` block from `helix.config.ts` |
88
90
  | `ctx.state` | Per-request scratch space |
@@ -254,10 +256,10 @@ Things to know:
254
256
  - Files and directories starting with `_` below `_scheduled/` are treated as helpers, not schedules — the only files that belong in the directory besides schedule definitions.
255
257
  - `getContext()` works inside schedule handlers; shared code can detect a scheduled run by checking for `ctx.trigger`.
256
258
 
257
- Limits — schedules run in the same deployed runtime as HTTP functions and share its execution limits:
259
+ Limits — schedules run in the same deployed runtime as HTTP functions but get a longer time limit:
258
260
 
259
- - **Handler time limit: 180 seconds.** A run still going at the limit is killed and counts as failed. Work that can't reliably finish in time should be split across runs — persist progress (for example in `ctx.kv()`) and continue on the next fire.
260
- - **Delivery is at-least-once.** A failed run — a thrown error, a timed-out handler, or an infrastructure failure — is retried once roughly five minutes later, then dropped. Write handlers to be idempotent: a retry re-runs the whole handler with the same `ctx.trigger.scheduledAt`.
261
+ - **Handler time limit: 15 minutes.** A run still going at the limit is killed and counts as failed. Work that can't reliably finish in time should be split across runs — persist progress (for example in `ctx.kv()`) and continue on the next fire.
262
+ - **Delivery is at-least-once.** A failed run — a thrown error, a timed-out handler, or an infrastructure failure — is retried once, usually about a minute later, then dropped. Write handlers to be idempotent: a retry re-runs the whole handler with the same `ctx.trigger.scheduledAt`.
261
263
  - **Highest frequency is once per minute** — 5-field cron has minute granularity.
262
264
  - **Memory is managed by the platform** and is not configurable per function.
263
265
  - Fires are scheduled for the exact cron minute, but execution can start late under load or on a cold start — compare `ctx.trigger.scheduledAt` (intended) with `ctx.trigger.firedAt` (actual) when lateness matters.
@@ -295,6 +297,8 @@ Things to know:
295
297
 
296
298
  - **Fire-and-forget only.** `callFunctionAsync` resolves once the call is accepted, not once the
297
299
  target runs — there is no result, status, or execution id to get back.
300
+ - **15-minute time limit.** The target runs with the same 15-minute handler time limit as a
301
+ scheduled function; a run still going at the limit is killed and counts as failed.
298
302
  - **Chaining is capped at two hops.** A normal (HTTP or scheduled) execution can call once; the
299
303
  execution it starts can call once more; a third hop is refused.
300
304
  - **The target must accept `POST`.** The call always dispatches as `POST`, regardless of the
@@ -383,6 +387,125 @@ export default defineFunction(async (ctx) => {
383
387
  and passing a model instance built directly against a third-party AI SDK provider (bypassing
384
388
  `ctx.ai`) throws `SdkError.aiForeignModelRejected`.
385
389
 
390
+ ## Agents and tools — `ctx.agent`
391
+
392
+ An **agent** is an AI loop you define once and run from any handler: it calls a model, decides
393
+ when to use the **tools** you gave it, and keeps a conversation **session** across turns. You
394
+ write agents and tools as files; `ctx.agent(name)` runs them.
395
+
396
+ - **Tools** (`defineTool`) live under `functions/_tools/` — a name, description, Zod `input`
397
+ schema, and a handler. A tool is a normal module you can also call in-process; when an agent
398
+ calls it, the same validation and handler run.
399
+ - **Agents** (`defineAgent`) live under `functions/_agents/`, one file per agent. The agent
400
+ declares its `model` and `auth` (an `aiProviders`/`authentications` alias, exactly like
401
+ `ctx.ai`), its `instructions`, and the `tools` it may call.
402
+
403
+ ```typescript
404
+ // functions/_tools/lookup_order.ts
405
+ import { defineTool } from '@trayai/helix-sdk';
406
+ import { z } from 'zod';
407
+
408
+ export default defineTool({
409
+ name: 'lookup_order',
410
+ description: 'Look up an order by its id.',
411
+ input: z.object({ orderId: z.string() }),
412
+ async handler(ctx) {
413
+ const res = await ctx.http.authed('shop').get(`https://api.shop.example/orders/${ctx.input.orderId}`);
414
+ return res.body; // { status, body?, headers } — see Authenticated HTTP
415
+ },
416
+ });
417
+ ```
418
+
419
+ ```typescript
420
+ // functions/_agents/support-agent.ts
421
+ import { defineAgent } from '@trayai/helix-sdk';
422
+ import lookupOrder from '../_tools/lookup_order.js';
423
+
424
+ export default defineAgent({
425
+ name: 'support-agent',
426
+ description: 'Answers customer support questions.',
427
+ model: 'claude-sonnet-4-5',
428
+ auth: 'anthropicKey', // an aiProviders alias, like ctx.ai
429
+ instructions: 'You are a helpful support agent. Use tools to look up real data.',
430
+ tools: [lookupOrder],
431
+ });
432
+ ```
433
+
434
+ Run it from any function:
435
+
436
+ ```typescript
437
+ import { defineFunction } from '@trayai/helix-sdk';
438
+ import { z } from 'zod';
439
+ import '../_agents/support-agent.js'; // register the agent (see note below)
440
+
441
+ export const input = z.object({
442
+ message: z.string(),
443
+ sessionId: z.string().optional(),
444
+ });
445
+
446
+ export default defineFunction<typeof input>(async (ctx) => {
447
+ const result = await ctx.agent('support-agent').generate({
448
+ prompt: ctx.input.message,
449
+ sessionId: ctx.input.sessionId, // omit to start a new conversation
450
+ });
451
+ return { text: result.text, sessionId: result.sessionId };
452
+ });
453
+ ```
454
+
455
+ - **`generate(options)`** runs the loop to completion and resolves with the model result plus
456
+ the `sessionId` it used. **`stream(options)`** returns the AI SDK stream result (with its
457
+ `sessionId`) for token-by-token responses. Both accept a `prompt` (or `messages`) and an
458
+ optional `sessionId`.
459
+ - **Deployed functions must import the agent module** (e.g. `import '../_agents/support-agent.js'`)
460
+ so it registers before `ctx.agent(name)` runs — only `helix dev` auto-loads `_agents/`; an
461
+ unknown name throws `Unknown agent "<name>"`.
462
+ - **`model` / `auth`** reference the same `aiProviders` + `authentications` aliases as
463
+ `ctx.ai`, so every provider works — including **Amazon Bedrock** (`auth` pointing at a
464
+ Bedrock authentication and a Bedrock model id). Declare one or more `fallbacks`
465
+ (`{ model, auth }` pairs) and the agent retries the next on a model error.
466
+ - **Tools** passed to `defineAgent` are given to the model automatically. Set
467
+ `needsApproval: true` (or a predicate of the input) on a tool and the loop pauses for human
468
+ approval before that tool runs.
469
+ - **Delegation** — list other agents' names in `agents: [...]` and the agent can hand work to
470
+ them as sub-agents (each keeps its own session; nesting is capped).
471
+
472
+ ### Sessions
473
+
474
+ A session is the **full record of a conversation**, not just the model's context window —
475
+ appends never delete, and there is no default expiry, so an app can always show a user their
476
+ earlier conversations. `ctx.agent(name).session(sessionId)` reads and manages one:
477
+
478
+ ```typescript
479
+ const agent = ctx.agent('support-agent');
480
+ const history = await agent.session(sessionId).messages(); // whole conversation
481
+ const page = await agent.session(sessionId).page({ limit: 50, order: 'desc' }); // newest first
482
+ await agent.session(sessionId).clear(); // delete the conversation
483
+ ```
484
+
485
+ - **`memory.maxSessionMessages`** (default 200) caps only what the **model** is sent each turn
486
+ — never what is stored. **`memory.ttl`** (seconds) is opt-in idle retention; omit it and
487
+ sessions are kept until you `clear()` them.
488
+ - **`memory.scope: 'user'`** keys sessions by the invoking user (`ctx.identity`), so each user
489
+ only sees their own; `agent.sessions({ first, cursor })` then lists the calling user's recent
490
+ sessions, newest first. The default scope is `'project'` (sessions shared across the
491
+ project's executions). `agent.sessions()` requires the **managed** store (below) and a
492
+ `'user'`-scoped agent — it is not supported on the bring-your-own DynamoDB store.
493
+
494
+ Choose where sessions are stored with the `agentSessions` field in `helix.config.ts`:
495
+
496
+ ```typescript
497
+ export default defineConfig({
498
+ // ...
499
+ // Managed by Helix (the default — nothing to configure):
500
+ agentSessions: { store: 'managed' },
501
+ // …or bring your own DynamoDB table (credentials injected by the platform):
502
+ // agentSessions: { store: 'dynamodb', auth: '<aws-alias>', table: 'agent-sessions', region: 'us-east-1' },
503
+ });
504
+ ```
505
+
506
+ Try agents locally with `helix dev`, then `helix agent list` and `helix agent chat <name>`
507
+ (see the `@trayai/helix-cli` README).
508
+
386
509
  ## Authentication
387
510
 
388
511
  Authenticated features (`ctx.http.authed`, `ctx.kv`, `ctx.files`, `ctx.ai`) require you to be logged in during local development:
@@ -1,5 +1,5 @@
1
1
  import { z, ZodType } from 'zod';
2
- import { P as PlatformContext } from './types-CRUtefiq.js';
2
+ import { P as PlatformContext } from './types-CVW_-1wh.js';
3
3
 
4
4
  interface SdkRuntimeConfig {
5
5
  /**
@@ -652,9 +652,6 @@ declare function requireWorkspaceId(config: LoadedTrayConfig): string;
652
652
  /**
653
653
  * `defineTool` (helix-spec 12) — the subset agents consume (helix-spec 14).
654
654
  *
655
- * **Beta.** Agents and tools are in beta: this API may change in a future
656
- * release without a major version bump.
657
- *
658
655
  * A tool is a *definition*: name, description, input schema, approval policy,
659
656
  * and handler together in one default export. Tools are:
660
657
  *
@@ -714,8 +711,6 @@ interface HelixToolLike {
714
711
  }
715
712
  /**
716
713
  * Define a tool an agent can call (or that your code can invoke in-process).
717
- *
718
- * @beta Agents and tools are in beta and may change in a future release.
719
714
  */
720
715
  declare function defineTool<TSchema extends ZodType>(config: DefineToolConfig<TSchema>): HelixTool<TSchema>;
721
716
  /** Structural check for defineTool output — see TOOL_DEFINITION_KIND. */
@@ -726,9 +721,6 @@ declare function isToolDefinition(value: unknown): value is HelixTool;
726
721
  * `functions/_agents/`, definitions in code, the file system as the source of
727
722
  * truth.
728
723
  *
729
- * **Beta.** Agents and tools are in beta: this API may change in a future
730
- * release without a major version bump.
731
- *
732
724
  * Like `defineSchedule`, the SDK owns the definition + runtime and the
733
725
  * host (dev server, lambda router) owns discovery: importing the module
734
726
  * registers the agent by name.
@@ -897,8 +889,6 @@ interface AgentDefinition extends z.output<typeof agentConfigSchema> {
897
889
  }
898
890
  /**
899
891
  * Define an agent (default export of a file under `functions/_agents/`).
900
- *
901
- * @beta Agents and tools are in beta and may change in a future release.
902
892
  */
903
893
  declare function defineAgent(config: AgentDefinitionConfig): AgentDefinition;
904
894
  /** Structural check for defineAgent output — see AGENT_DEFINITION_KIND. */
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as h3 from 'h3';
2
2
  import { ZodType } from 'zod';
3
- import { F as FunctionHandler, D as DefineFunctionOptions, a as DefineScheduleConfig, S as ScheduleDefinition, P as PlatformContext } from './types-CRUtefiq.js';
4
- export { A as AgentApprovalDecision, b as AgentCallOptions, c as AgentClient, d as AgentPendingApproval, e as AgentResult, f as AgentSession, g as AgentSessionPage, h as AgentSessionPageOptions, i as AgentSessionSummary, j as AgentSessionsList, k as AgentStreamResult, l as AiEmbeddingModelInstance, m as AiImageModelInstance, n as AiLanguageModelInstance, o as AiSpeechModelInstance, p as AiTranscriptionModelInstance, B as BrokerAuthedClient, q as BrokerCallOptions, r as BrokerCallResult, C as CallFunctionAsync, s as DbCallParameters, t as DbClient, u as FileSystemClient, H as HelixAI, v as HelixAIProvider, w as HelixAgent, x as HelixCost, y as HelixResultMeta, z as HttpClient, K as KeyValueStore, L as Logger, E as S3SignOptions, G as S3SignResult, I as ScheduleContext, J as ScheduleHandler, M as ScheduleTrigger, N as SqlBuilder, T as TrayContext, U as UnvalidatedInput } from './types-CRUtefiq.js';
5
- import { T as TrayConfig, L as LoadedTrayConfig, W as WatchErrorPhase } from './define-agent-Cc6mFat1.js';
6
- export { A as AGENT_DEFINITION_KIND, a as AI_SERVICES, b as AgentDefinition, c as AgentDefinitionConfig, d as AgentSessionsConfig, e as AiProviderEntry, f as AiService, C as ConfigFileOptions, D as DefineToolConfig, H as HELIX_CONFIG_ENV, g as HelixTool, h as HelixToolLike, P as ProvisionedTrayConfig, S as SdkRuntimeConfig, i as TOOL_DEFINITION_KIND, U as UnprovisionedTrayConfig, j as WORKSPACE_ID_REQUIRED_CODE, k as WorkspaceIdRequiredError, l as agentSessionsSchema, m as aiProviderEntrySchema, n as defineAgent, o as defineTool, p as getSdkConfig, q as isAgentDefinition, r as isToolDefinition, s as loadConfig, t as loadedTrayConfigSchema, u as projectIdSchema, v as requireWorkspaceId, w as resolveConfigFile, x as resolveConfigOverride, y as workspaceIdSchema } from './define-agent-Cc6mFat1.js';
3
+ import { F as FunctionHandler, D as DefineFunctionOptions, a as DefineScheduleConfig, S as ScheduleDefinition, P as PlatformContext } from './types-CVW_-1wh.js';
4
+ export { A as AgentApprovalDecision, b as AgentCallOptions, c as AgentClient, d as AgentPendingApproval, e as AgentResult, f as AgentSession, g as AgentSessionPage, h as AgentSessionPageOptions, i as AgentSessionSummary, j as AgentSessionsList, k as AgentStreamResult, l as AiEmbeddingModelInstance, m as AiImageModelInstance, n as AiLanguageModelInstance, o as AiSpeechModelInstance, p as AiTranscriptionModelInstance, B as BrokerAuthedClient, q as BrokerCallOptions, r as BrokerCallResult, C as CallFunctionAsync, s as DbCallParameters, t as DbClient, u as FileSystemClient, H as HelixAI, v as HelixAIProvider, w as HelixAgent, x as HelixCost, y as HelixResultMeta, z as HttpClient, K as KeyValueStore, L as Logger, E as S3SignOptions, G as S3SignResult, I as ScheduleContext, J as ScheduleHandler, M as ScheduleTrigger, N as SqlBuilder, T as TrayContext, U as UnvalidatedInput } from './types-CVW_-1wh.js';
5
+ import { T as TrayConfig, L as LoadedTrayConfig, W as WatchErrorPhase } from './define-agent-DXV_nHvs.js';
6
+ export { A as AGENT_DEFINITION_KIND, a as AI_SERVICES, b as AgentDefinition, c as AgentDefinitionConfig, d as AgentSessionsConfig, e as AiProviderEntry, f as AiService, C as ConfigFileOptions, D as DefineToolConfig, H as HELIX_CONFIG_ENV, g as HelixTool, h as HelixToolLike, P as ProvisionedTrayConfig, S as SdkRuntimeConfig, i as TOOL_DEFINITION_KIND, U as UnprovisionedTrayConfig, j as WORKSPACE_ID_REQUIRED_CODE, k as WorkspaceIdRequiredError, l as agentSessionsSchema, m as aiProviderEntrySchema, n as defineAgent, o as defineTool, p as getSdkConfig, q as isAgentDefinition, r as isToolDefinition, s as loadConfig, t as loadedTrayConfigSchema, u as projectIdSchema, v as requireWorkspaceId, w as resolveConfigFile, x as resolveConfigOverride, y as workspaceIdSchema } from './define-agent-DXV_nHvs.js';
7
7
  export { a as REGION_VALUES, R as Region, r as regionSchema } from './region-schema-COfWyGI9.js';
8
8
  import { StopCondition, ToolSet } from 'ai';
9
9
  export { EmbedManyResult, EmbedResult, EmbeddingModel, FinishReason, GenerateImageResult, GenerateObjectResult, GenerateTextResult, ImageModel, LanguageModel, LanguageModelUsage, ModelMessage, Output, PrepareStepFunction, SpeechModel, SpeechResult, StopCondition, StreamObjectResult, StreamTextResult, TextStreamPart, ToolChoice, ToolSet, TranscriptionModel, TranscriptionResult, UIMessage, convertToModelMessages, cosineSimilarity, dynamicTool, hasToolCall, jsonSchema, smoothStream, stepCountIs, tool, zodSchema } from 'ai';
@@ -1,7 +1,7 @@
1
- import { L as LoadedTrayConfig, b as AgentDefinition } from '../define-agent-Cc6mFat1.js';
2
- export { z as SdkConfigInput, B as setSdkConfig } from '../define-agent-Cc6mFat1.js';
3
- import { j as AgentSessionsList, b as AgentCallOptions, e as AgentResult } from '../types-CRUtefiq.js';
4
- export { O as SessionExpiredError, Q as clearAgentSessions } from '../types-CRUtefiq.js';
1
+ import { L as LoadedTrayConfig, b as AgentDefinition } from '../define-agent-DXV_nHvs.js';
2
+ export { z as SdkConfigInput, B as setSdkConfig } from '../define-agent-DXV_nHvs.js';
3
+ import { j as AgentSessionsList, b as AgentCallOptions, e as AgentResult } from '../types-CVW_-1wh.js';
4
+ export { O as SessionExpiredError, Q as clearAgentSessions } from '../types-CVW_-1wh.js';
5
5
  import 'zod';
6
6
  import 'h3';
7
7
  import 'ky';
@@ -1,4 +1,4 @@
1
- import { P as PlatformContext } from '../types-CRUtefiq.js';
1
+ import { P as PlatformContext } from '../types-CVW_-1wh.js';
2
2
  import 'h3';
3
3
  import 'ky';
4
4
  import 'zod';
@@ -392,8 +392,6 @@ type AgentStreamResult = StreamTextReturn & {
392
392
  };
393
393
  /**
394
394
  * What `ctx.agent(name)` returns.
395
- *
396
- * @beta Agents and tools are in beta and may change in a future release.
397
395
  */
398
396
  interface HelixAgent {
399
397
  /** The AI SDK loop + session handling. */
@@ -422,8 +420,6 @@ interface HelixAgent {
422
420
  }
423
421
  /**
424
422
  * `ctx.agent` — look up a registered agent by name.
425
- *
426
- * @beta Agents and tools are in beta and may change in a future release.
427
423
  */
428
424
  type AgentClient = (name: string) => HelixAgent;
429
425
 
@@ -517,8 +513,6 @@ interface ContextCore {
517
513
  ai: HelixAI;
518
514
  /**
519
515
  * Agent client (helix-spec 14): `ctx.agent(name).generate()/.stream()`.
520
- *
521
- * @beta Agents and tools are in beta and may change in a future release.
522
516
  */
523
517
  agent: AgentClient;
524
518
  log: Logger;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trayai/helix-sdk",
3
- "version": "1.8.0",
3
+ "version": "1.13.1",
4
4
  "description": "Helix SDK runtime — defineFunction, ctx, defineConfig, authed HTTP",
5
5
  "license": "Apache-2.0",
6
6
  "author": "trayio",