@betterlu/agentlu 1.11.0 → 2.0.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.
package/README.md CHANGED
@@ -10,7 +10,19 @@ const client = new OpenAI({ baseURL: "http://localhost:8912/v1", apiKey });
10
10
  const r = await client.responses.create({ model: "fast", input: "hi" });
11
11
  ```
12
12
 
13
- This client adds get-or-create registration, typed `runJson` / `runText`, use-case catalogs, the two `/v1` tiers (`llm.*` / `agent.*`), error classification (`err.kind`, `isUnavailable`), background `wait`, bulk uploads, client-side `timeoutMs`, and auto-retry on `409 thread_busy`.
13
+ This client adds get-or-create registration, typed `runJson` / `runText`, use-case catalogs, error classification (`err.kind`, `isUnavailable`), background `wait`, bulk uploads, client-side `timeoutMs`, and auto-retry on `409 thread_busy`.
14
+
15
+ ## SDK 2.0 surface
16
+
17
+ SDK 2.0 removes the unused direct-call `llm.*` and `typedStream` wrappers, the
18
+ Briefs publishing/reader helpers, and the discovery helpers for agents, models,
19
+ tools, health and the current client. The matching `/v1/briefs`, `/v1/agents`,
20
+ `/v1/models`, `/v1/tools` and `/v1/me` routes are no longer served. Use the
21
+ ordinary `runText` / `runJson` methods with `agent: "direct"` for direct calls.
22
+
23
+ `/v1/health` remains available and `waitForReady` still polls it; `/v1/threads`
24
+ and the SDK `threads` helpers remain available. The server also retains
25
+ `/v1/chat/completions` for OpenAI-compatible callers.
14
26
 
15
27
  ## Install
16
28
 
@@ -35,10 +47,11 @@ console.log(response.output_text);
35
47
 
36
48
  ## Two tiers
37
49
 
38
- `/v1` has two documented tiers, and 1.8 exposes both as namespaces. Pick one and
39
- stay there (see the `agentlu-api` skill for the full contract):
50
+ `/v1` supports direct and agent runs through the same run methods. Use
51
+ `agent: "direct"` for one profile-free call or name an agent for its profile
52
+ and tools (see the `agentlu-api` skill for the full contract):
40
53
 
41
- | | `alu.llm.*` (direct) | `alu.agent.*` (agent) |
54
+ | | Direct | Agent |
42
55
  |---|---|---|
43
56
  | What runs | one profile-free provider call | profile + tool families + agent loop |
44
57
  | Session | none (`store: false`) | a real thread you can continue |
@@ -46,21 +59,16 @@ stay there (see the `agentlu-api` skill for the full contract):
46
59
  | Use it for | extraction, classification, short answers | research, phone/browser work, context |
47
60
 
48
61
  ```ts
49
- // Direct tier.
50
- const { text } = await alu.llm.text("Name three colours.");
51
- const { data } = await alu.llm.json<{ items: string[] }>(
52
- { type: "object", properties: { items: { type: "array", items: { type: "string" } } }, required: ["items"] },
53
- "two milk, one bread",
54
- );
55
- for await (const event of alu.llm.stream("Count to three")) console.log(event.type);
62
+ // Direct tier: explicit opt-in, no tools or session.
63
+ const { text } = await alu.runText({ agent: "direct", input: "Name three colours." });
56
64
 
57
65
  // Agent tier (default agent `api`; pin fast/thorough/… or "<app>/<name>").
58
66
  const run = await alu.agent.run({ agent: "fast", input: "what changed in node 24?" });
59
67
  const done = await alu.agent.background({ input: "research this deeply" }, { timeoutMs: 600_000 });
60
68
  ```
61
69
 
62
- `alu.run` / `runJson` / `runText` / `stream` remain the agent-tier aliases they
63
- always were - nothing breaks by upgrading.
70
+ `alu.run` / `runJson` / `runText` / `stream` remain available for Responses
71
+ runs, including calls that explicitly select the direct tier.
64
72
 
65
73
  ## Errors: `kind` and fail-open
66
74
 
@@ -72,7 +80,7 @@ saturation, timeout, rate limit):
72
80
  import { isUnavailable } from "@betterlu/agentlu";
73
81
 
74
82
  try {
75
- await alu.llm.text(input);
83
+ await alu.runText({ agent: "direct", input });
76
84
  } catch (err) {
77
85
  if (isUnavailable(err)) return fallbackAnswer(); // degrade gracefully
78
86
  throw err;
@@ -236,7 +244,7 @@ Plain text (throws unless `status === "completed"` with non-empty `output_text`)
236
244
  const { text } = await ai.tag.runText({ input: "summarize this" });
237
245
  ```
238
246
 
239
- `timeoutMs` aborts the HTTP attempt and, when `timeout_ms` is omitted, is also sent as the server-side run budget. Constructor `new AgentLu({ timeoutMs: 30_000 })` is the default for calls that omit it.
247
+ `timeoutMs` aborts the HTTP attempt and, when `timeout_ms` is omitted, is also sent as the server-side run budget. Constructor `new AgentLu({ timeoutMs: 30_000 })` is the default for calls that omit it. The server rejects `timeout_ms` below 15 000 ms and `max_output_tokens` below 256 with a 400 naming the minimum; `/v1/chat/completions` applies the same minimum to `max_tokens` / `max_completion_tokens`. Registered defaults below either minimum are clamped up with a once-per-client warning.
240
248
 
241
249
  Upload-and-run:
242
250
 
@@ -295,8 +303,8 @@ if (answers.team.type === "choice") return lookupOrder(answers.team.choice);
295
303
  | `score` | `score`, `confidence`, `legend`, `probabilities` per step |
296
304
 
297
305
  `decisions.ask()` is the same call returning only the answers map.
298
- `decisions.askOrNull()` is fail-open (`null` on unconfigured/error). Discover the
299
- model in `GET /v1/models` (`harness: "systemone"`); it is only callable on
306
+ `decisions.askOrNull()` is fail-open (`null` on unconfigured/error). The
307
+ decision model is only callable on
300
308
  `POST /v1/decisions`, sync, no streaming. A missing key surfaces as HTTP 503
301
309
  `systemone_unconfigured` (not retried by the SDK). Use-case runners expose the
302
310
  same `decisions` helpers on their own key.
@@ -371,7 +379,7 @@ feature the SDK lacks: add it here and publish).
371
379
  2. Bump the version: `npm version <x.y.z> --no-git-tag-version` (minor for new
372
380
  methods/fields, patch for fixes, major for breaking changes).
373
381
  3. Add a `CHANGELOG.md` entry for that version.
374
- 4. Verify: `npm run build` here and `npx vitest run tests/sdk` from the repo root.
382
+ 4. Verify: `npm run build` here and `npm test -- tests/sdk` from the repo root.
375
383
  5. Publish: `npm publish` (runs `prepublishOnly` → build; npm user `betterlu`).
376
384
  Check with `npm view @betterlu/agentlu version`.
377
385
  6. Commit the bump with the change, then update consumers to the new range
@@ -8,77 +8,6 @@
8
8
  * contract. They describe the bytes on the wire (snake_case); the SDK's own
9
9
  * types are the ergonomic view over them.
10
10
  */
11
- export interface WireBriefPublishInput {
12
- "source": string;
13
- "key": string;
14
- "kind": "edition" | "report" | "note" | "story";
15
- "audience": "larry" | "misa" | "both";
16
- "title": string;
17
- "dek"?: string;
18
- "body"?: string;
19
- "bodyFormat"?: "markdown" | "html";
20
- "entries"?: Array<{
21
- "title": string;
22
- "url"?: string;
23
- "image"?: string;
24
- "chips"?: string[];
25
- "body"?: string;
26
- }>;
27
- "images"?: string[];
28
- "url"?: string;
29
- "keep"?: boolean;
30
- "ttlDays"?: number;
31
- "collection"?: string;
32
- "sourceLabel"?: string;
33
- "sourceEmoji"?: string;
34
- "coverArt"?: boolean;
35
- "jobRunId"?: string;
36
- "artifactId"?: string;
37
- "publishedAt"?: string;
38
- }
39
- export interface WireBriefDetail {
40
- "id": string;
41
- "source": string;
42
- "sourceLabel": string;
43
- "sourceEmoji": string | null;
44
- "kind": "edition" | "report" | "note" | "story";
45
- "audience": "larry" | "misa" | "both";
46
- "title": string;
47
- "dek": string | null;
48
- "coverUrl": string | null;
49
- "coverArtStatus": "none" | "pending" | "ready" | "failed";
50
- "edition": {
51
- "hero": string;
52
- "highlights": string[];
53
- } | null;
54
- "keep": boolean;
55
- "collection": string | null;
56
- "readingMinutes": number | null;
57
- "publishedAt": string;
58
- "bodyFormat": "markdown" | "html";
59
- "bodyHtml": string | null;
60
- "frameUrl": string | null;
61
- "entries": Array<{
62
- "title": string;
63
- "url"?: string;
64
- "image"?: string;
65
- "chips"?: string[];
66
- "body"?: string;
67
- "bodyHtml"?: string;
68
- }> | null;
69
- "images": string[];
70
- "url": string | null;
71
- "jobRunId": string | null;
72
- "artifactId": string | null;
73
- "expiresAt": string | null;
74
- }
75
- export interface WireBriefPublishResult {
76
- "id": string;
77
- "url": string;
78
- "coverUrl": string | null;
79
- "coverArtStatus": "none" | "pending" | "ready" | "failed";
80
- "updated": boolean;
81
- }
82
11
  export interface WireHouseholdSignalInput {
83
12
  "source": string;
84
13
  "kind": string;
@@ -97,7 +26,7 @@ export interface WireHouseholdSignalResult {
97
26
  export interface WireCreateResponse {
98
27
  /** Execution backend. */
99
28
  "backend"?: "pi";
100
- /** Model id, or an agent name (stock OpenAI clients can only set `model`). Harness-qualified ids run other runtimes: `google/<id>` selects an Antigravity model on the Google agent. See GET /v1/models and GET /v1/models?harness=google. */
29
+ /** Model id, or an agent name (stock OpenAI clients can only set `model`). Harness-qualified ids run other runtimes: `google/<id>` selects an Antigravity model on the Google agent. */
101
30
  "model"?: string;
102
31
  "input"?: string | Array<{
103
32
  "role": "user" | "assistant" | "system" | "developer";
@@ -130,7 +59,7 @@ export interface WireCreateResponse {
130
59
  "conversation"?: string | {
131
60
  "id": string;
132
61
  };
133
- /** Optional and discouraged. Omit it to use the model's own output limit; values here are applied verbatim. If the limit is reached, the HTTP 200 Response has status `incomplete`, reason `max_output_tokens`, and may retain partial output. */
62
+ /** Optional and discouraged. Minimum 256 tokens; omit it to use the model's own output limit; values here are applied verbatim. A registered client default below the minimum is clamped up. If the limit is reached, the HTTP 200 Response has status `incomplete`, reason `max_output_tokens`, and may retain partial output. */
134
63
  "max_output_tokens"?: number;
135
64
  "temperature"?: number;
136
65
  "text"?: {
@@ -156,13 +85,13 @@ export interface WireCreateResponse {
156
85
  "tool_choice"?: "auto" | "none" | "required";
157
86
  "metadata"?: Record<string, string>;
158
87
  "include"?: Array<"reasoning" | "rounds" | "subagents" | "artifacts">;
159
- /** Which agent runs the request. The recommended general machine agent is `api`, which has no persona: `instructions` replace its system prompt. Pin `fast` for the chat-tuned version. `direct` selects the direct tier: the profile-free `api` agent with no tools and no session (see the Tiers section). `household/<slug>` runs a household agent built in the Agents studio (list them at GET /v1/agents). An `<app>/<name>` id runs an agent the caller's app declared at registration. `research` is an alias for `thorough` with Report output (a sourced report artifact). Retired ids (`mealu`, `nestlu`, `kitchen`, `waterlu`, `money`, `swarm`, `storylu`, `google-research`, `google-image`, `android`) return HTTP 400 `unknown_agent` with a pointer to their successor; the Android phone is now the `android` tool family on `assistant`. */
160
- "agent"?: "auto" | "fast" | "thorough" | "assistant" | "code" | "google" | "image" | "api" | "digest" | "herald" | "cradle" | "custom" | "direct" | string | "mealu" | "nestlu" | "kitchen" | "waterlu" | "money" | "swarm" | "stage" | "roleplay" | "storylu" | "google-research" | "google-image" | "android" | "research";
88
+ /** Agent id. Built-in agents, `direct`, the `research` alias, declared app agents (`<app>/<name>`), and household agents (`household/<slug>`) are accepted; unknown ids return HTTP 400 `unknown_agent`. */
89
+ "agent"?: string;
161
90
  /** Thinking level. Explicit `effort: "off"` is honored; other requests are clamped to the selected model's supported capabilities. The SDK does not promise provider benchmark parity. */
162
91
  "reasoning"?: {
163
92
  "effort"?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
164
93
  };
165
- /** Wall clock for this run. Default: the use-case tier's (45s instant / 180s standard / 600s deep). */
94
+ /** Wall clock for this run. Minimum 15000 ms (15 s); a registered client default below it is clamped up. Default: the use-case tier's (45s instant / 180s standard / 600s deep). */
166
95
  "timeout_ms"?: number;
167
96
  /** Provider attempts for this run (1 = none). Bounds model-chain fallbacks. Default: the use-case tier's (instant 1, standard 2, deep 3) when the client declares a profile; without one the run keeps the pre-tier budget (the direct tier walks its whole chain, the agent tier does not fall back). */
168
97
  "attempts"?: number;
@@ -174,7 +103,7 @@ export interface WireCreateResponse {
174
103
  "end_user"?: string;
175
104
  }
176
105
  export interface WireChatCompletionRequest {
177
- /** An agentlu model id (GET /v1/models) or `direct`. Omit it to let the model chain pick. An unknown id is HTTP 400 `unknown_model`. */
106
+ /** An AgentLu model id or `direct`. Omit it to let the model chain pick. An unknown id is HTTP 400 `unknown_model`. */
178
107
  "model"?: string;
179
108
  /** system/developer messages become the run's instructions; the rest is folded into the prompt with role tags. Tool messages are rejected (unsupported_tool): the direct tier runs no tools. */
180
109
  "messages": Array<{
@@ -235,9 +164,9 @@ export interface WireRegisterClientRequest {
235
164
  /** Run defaults applied when a request omits the field: request > registered client default > use-case tier > agent/profile default. The built-in `store` default is true. Register one client per use-case (e.g. mealu-enrich) with its system prompt and tools baked in. */
236
165
  "defaults"?: {
237
166
  "backend"?: "pi";
238
- "agent"?: "auto" | "fast" | "thorough" | "assistant" | "code" | "google" | "image" | "api" | "digest" | "herald" | "cradle" | "custom" | "direct" | string | "mealu" | "nestlu" | "kitchen" | "waterlu" | "money" | "swarm" | "stage" | "roleplay" | "storylu" | "google-research" | "google-image" | "android" | "research";
167
+ "agent"?: "auto" | "fast" | "thorough" | "assistant" | "google" | "api" | "digest" | "herald" | "cradle" | "custom" | "direct" | string | "research";
239
168
  "model"?: string;
240
- "modelRoute"?: "chat.quick" | "chat.household" | "chat.deep" | "chat.code" | "device" | "background.digest" | "utility" | "memory.extract" | "memory.judge" | "memory.consolidate";
169
+ "modelRoute"?: "chat.quick" | "chat.household" | "chat.deep" | "device" | "background.digest" | "utility" | "memory.extract" | "memory.judge" | "memory.consolidate";
241
170
  "instructions"?: string;
242
171
  "temperature"?: number;
243
172
  "store"?: boolean;
@@ -286,12 +215,11 @@ export interface WireRegisterClientRequest {
286
215
  /** Run defaults applied when a request omits the field: request > registered client default > use-case tier > agent/profile default. The built-in `store` default is true. Register one client per use-case (e.g. mealu-enrich) with its system prompt and tools baked in. */
287
216
  export interface WireClientDefaults {
288
217
  "backend"?: "pi";
289
- /** Which agent runs the request. The recommended general machine agent is `api`, which has no persona: `instructions` replace its system prompt. Pin `fast` for the chat-tuned version. `direct` selects the direct tier: the profile-free `api` agent with no tools and no session (see the Tiers section). `household/<slug>` runs a household agent built in the Agents studio (list them at GET /v1/agents). An `<app>/<name>` id runs an agent the caller's app declared at registration. `research` is an alias for `thorough` with Report output (a sourced report artifact). Retired ids (`mealu`, `nestlu`, `kitchen`, `waterlu`, `money`, `swarm`, `storylu`, `google-research`, `google-image`, `android`) return HTTP 400 `unknown_agent` with a pointer to their successor; the Android phone is now the `android` tool family on `assistant`. */
290
- "agent"?: "auto" | "fast" | "thorough" | "assistant" | "code" | "google" | "image" | "api" | "digest" | "herald" | "cradle" | "custom" | "direct" | string | "mealu" | "nestlu" | "kitchen" | "waterlu" | "money" | "swarm" | "stage" | "roleplay" | "storylu" | "google-research" | "google-image" | "android" | "research";
291
- /** ModelConfig id (GET /v1/models). Stock clients may also use an agent name here; prefer explicit `agent` for machine calls. */
218
+ "agent"?: "auto" | "fast" | "thorough" | "assistant" | "google" | "api" | "digest" | "herald" | "cradle" | "custom" | "direct" | string | "research";
219
+ /** Configured model id. Stock clients may also use an agent name here; prefer explicit `agent` for machine calls. */
292
220
  "model"?: string;
293
221
  /** Task route whose pool order and effort apply to automatic model selection. Mutually exclusive with model. Explicit request models, builtin chat agents, and agent model pins win; app-owned and api agents inherit the client route. */
294
- "modelRoute"?: "chat.quick" | "chat.household" | "chat.deep" | "chat.code" | "device" | "background.digest" | "utility" | "memory.extract" | "memory.judge" | "memory.consolidate";
222
+ "modelRoute"?: "chat.quick" | "chat.household" | "chat.deep" | "device" | "background.digest" | "utility" | "memory.extract" | "memory.judge" | "memory.consolidate";
295
223
  /** System prompt for every run of this client. */
296
224
  "instructions"?: string;
297
225
  "temperature"?: number;
@@ -322,8 +250,9 @@ export interface WireClientDefaults {
322
250
  "url": string;
323
251
  "allowed_tools"?: string[];
324
252
  }>;
253
+ /** Default wall clock when the request omits `timeout_ms`. Values below 15000 ms are clamped up at run time (with a once-per-client warning). */
325
254
  "timeoutMs"?: number;
326
- /** Default output cap when the request omits `max_output_tokens`. The use-case tier supplies one when this is unset (instant 2048, deep 8192, standard none); requests always win. Honored for defaults written after this release: a value stored earlier stays inert until the app re-declares its defaults (or the console edits them), so a re-enable can never silently cap runs that used to complete. */
255
+ /** Default output cap when the request omits `max_output_tokens`. Values below 256 tokens are clamped up at run time (with a once-per-client warning). The use-case tier supplies one when this is unset (instant 2048, deep 8192, standard none); requests always win. Honored for defaults written after this release: a value stored earlier stays inert until the app re-declares its defaults (or the console edits them), so a re-enable can never silently cap runs that used to complete. */
327
256
  "maxOutputTokens"?: number;
328
257
  /** Provider attempts per run (1 = none). Bounds model-chain fallbacks, and is the background queue's retry budget. Defaults to the tier's (instant 1, standard 2, deep 3) when `use_case_profile.priority` is declared; without one the run keeps the pre-tier budget. */
329
258
  "attempts"?: number;
@@ -352,7 +281,7 @@ export interface WireAppAgentDeclaration {
352
281
  }
353
282
  export interface WireCreateThreadRequest {
354
283
  "title"?: string;
355
- "agent"?: "auto" | "fast" | "thorough" | "assistant" | "code" | "google" | "image" | "api" | "digest" | "herald" | "cradle" | "custom" | "research" | string;
284
+ "agent"?: "auto" | "fast" | "thorough" | "assistant" | "google" | "api" | "digest" | "herald" | "cradle" | "custom" | "research" | string;
356
285
  "model"?: string;
357
286
  "person"?: string | null;
358
287
  "owner"?: "client" | "person";
@@ -388,7 +317,7 @@ export interface WireResponse {
388
317
  "created_at": number;
389
318
  "status": "queued" | "in_progress" | "completed" | "failed" | "incomplete" | "cancelled";
390
319
  "backend": "pi";
391
- "agent": "auto" | "fast" | "thorough" | "assistant" | "code" | "google" | "image" | "api" | "digest" | "herald" | "cradle" | "custom";
320
+ "agent": "auto" | "fast" | "thorough" | "assistant" | "google" | "api" | "digest" | "herald" | "cradle" | "custom";
392
321
  "model": string;
393
322
  "conversation"?: {
394
323
  "id": string;
@@ -458,7 +387,7 @@ export interface WireResponse {
458
387
  "thread_id"?: string | null;
459
388
  "retries"?: number;
460
389
  "effective_model"?: string | null;
461
- "model_route"?: "chat.quick" | "chat.household" | "chat.deep" | "chat.code" | "device" | "background.digest" | "utility" | "memory.extract" | "memory.judge" | "memory.consolidate";
390
+ "model_route"?: "chat.quick" | "chat.household" | "chat.deep" | "device" | "background.digest" | "utility" | "memory.extract" | "memory.judge" | "memory.consolidate";
462
391
  "service_tier"?: "standard" | "priority";
463
392
  "execution_path"?: string | null;
464
393
  "queue_wait_ms"?: number | null;
@@ -578,7 +507,7 @@ export interface WireThread {
578
507
  "created_at": number;
579
508
  "updated_at": number;
580
509
  "title": string;
581
- "agent": "auto" | "fast" | "thorough" | "assistant" | "code" | "google" | "image" | "api" | "digest" | "herald" | "cradle" | "custom";
510
+ "agent": "auto" | "fast" | "thorough" | "assistant" | "google" | "api" | "digest" | "herald" | "cradle" | "custom";
582
511
  "model": string | null;
583
512
  /** "api" for threads created through /v1; "chat" when a human started it. */
584
513
  "origin": string;
@@ -617,9 +546,9 @@ export interface WireClient {
617
546
  "allow_person_threads"?: boolean;
618
547
  "defaults"?: {
619
548
  "backend"?: "pi";
620
- "agent"?: "auto" | "fast" | "thorough" | "assistant" | "code" | "google" | "image" | "api" | "digest" | "herald" | "cradle" | "custom" | "direct" | string | "mealu" | "nestlu" | "kitchen" | "waterlu" | "money" | "swarm" | "stage" | "roleplay" | "storylu" | "google-research" | "google-image" | "android" | "research";
549
+ "agent"?: "auto" | "fast" | "thorough" | "assistant" | "google" | "api" | "digest" | "herald" | "cradle" | "custom" | "direct" | string | "research";
621
550
  "model"?: string;
622
- "modelRoute"?: "chat.quick" | "chat.household" | "chat.deep" | "chat.code" | "device" | "background.digest" | "utility" | "memory.extract" | "memory.judge" | "memory.consolidate";
551
+ "modelRoute"?: "chat.quick" | "chat.household" | "chat.deep" | "device" | "background.digest" | "utility" | "memory.extract" | "memory.judge" | "memory.consolidate";
623
552
  "instructions"?: string;
624
553
  "temperature"?: number;
625
554
  "store"?: boolean;
@@ -683,51 +612,6 @@ export interface WireError {
683
612
  "retryable": boolean;
684
613
  };
685
614
  }
686
- export interface WireAgentInfo {
687
- /** A builtin agent id, or `household/<slug>` for an agent built in the household studio. */
688
- "id": string;
689
- "object": "agent";
690
- "profile": string;
691
- "description": string;
692
- "tools": string[];
693
- /** Tool families a /v1 caller may request for this agent. */
694
- "available_tools": Array<"web_search" | "fetch_content" | "hublu" | "memory" | "image" | "browser" | "android">;
695
- "supports_images": boolean;
696
- /** Long-running agents are best used with `background: true`. */
697
- "long_running": boolean;
698
- /** Runtime that serves this agent. */
699
- "harness": "pi" | "google";
700
- /** Household agents only: the capability ids the agent was built with. */
701
- "capabilities"?: string[];
702
- }
703
- export interface WireModelInfo {
704
- "id": string;
705
- "object": "model";
706
- "owned_by": string;
707
- "label": string;
708
- "input": Array<"text" | "image" | "video">;
709
- "available": boolean;
710
- /** True for the default entry within this model's harness. */
711
- "default": boolean;
712
- /** Runtime that serves this model. */
713
- "harness": "pi" | "google" | "systemone";
714
- /** Reasoning levels the model accepts (google models: the values the ACP thought_level option advertises). */
715
- "efforts"?: Array<"off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max">;
716
- /** Present on decision models: how to call them. */
717
- "decision"?: {
718
- "endpoint": "/v1/decisions";
719
- "question_types": Array<"noul" | "choice" | "score">;
720
- };
721
- }
722
- export interface WireToolInfo {
723
- "type": "web_search" | "fetch_content" | "hublu" | "memory" | "image" | "browser" | "android";
724
- "object": "tool";
725
- "description": string;
726
- /** Concrete tool names this family expands to. */
727
- "expands_to": string[];
728
- /** False when the backing service (e.g. hublu) is unreachable right now. */
729
- "available": boolean;
730
- }
731
615
  export interface WireStreamEvent {
732
616
  "type": string;
733
617
  "sequence_number"?: number;
@@ -743,7 +627,7 @@ export interface WireResponseList {
743
627
  "created_at": number;
744
628
  "status": "queued" | "in_progress" | "completed" | "failed" | "incomplete" | "cancelled";
745
629
  "backend": "pi";
746
- "agent": "auto" | "fast" | "thorough" | "assistant" | "code" | "google" | "image" | "api" | "digest" | "herald" | "cradle" | "custom";
630
+ "agent": "auto" | "fast" | "thorough" | "assistant" | "google" | "api" | "digest" | "herald" | "cradle" | "custom";
747
631
  "model": string;
748
632
  "conversation"?: {
749
633
  "id": string;
@@ -808,7 +692,7 @@ export interface WireResponseList {
808
692
  "thread_id"?: string | null;
809
693
  "retries"?: number;
810
694
  "effective_model"?: string | null;
811
- "model_route"?: "chat.quick" | "chat.household" | "chat.deep" | "chat.code" | "device" | "background.digest" | "utility" | "memory.extract" | "memory.judge" | "memory.consolidate";
695
+ "model_route"?: "chat.quick" | "chat.household" | "chat.deep" | "device" | "background.digest" | "utility" | "memory.extract" | "memory.judge" | "memory.consolidate";
812
696
  "service_tier"?: "standard" | "priority";
813
697
  "execution_path"?: string | null;
814
698
  "queue_wait_ms"?: number | null;
@@ -878,7 +762,7 @@ export interface WireThreadList {
878
762
  "created_at": number;
879
763
  "updated_at": number;
880
764
  "title": string;
881
- "agent": "auto" | "fast" | "thorough" | "assistant" | "code" | "google" | "image" | "api" | "digest" | "herald" | "cradle" | "custom";
765
+ "agent": "auto" | "fast" | "thorough" | "assistant" | "google" | "api" | "digest" | "herald" | "cradle" | "custom";
882
766
  "model": string | null;
883
767
  "origin": string;
884
768
  "end_user"?: string | null;
@@ -929,52 +813,3 @@ export interface WireFileList {
929
813
  /** Opaque keyset cursor; null on the last page. */
930
814
  "next_cursor": string | null;
931
815
  }
932
- export interface WireAgentList {
933
- "object": "list";
934
- "data": Array<{
935
- "id": string;
936
- "object": "agent";
937
- "profile": string;
938
- "description": string;
939
- "tools": string[];
940
- "available_tools": Array<"web_search" | "fetch_content" | "hublu" | "memory" | "image" | "browser" | "android">;
941
- "supports_images": boolean;
942
- "long_running": boolean;
943
- "harness": "pi" | "google";
944
- "capabilities"?: string[];
945
- }>;
946
- /** Opaque keyset cursor; null on the last page. */
947
- "next_cursor": string | null;
948
- }
949
- export interface WireModelList {
950
- "object": "list";
951
- "data": Array<{
952
- "id": string;
953
- "object": "model";
954
- "owned_by": string;
955
- "label": string;
956
- "input": Array<"text" | "image" | "video">;
957
- "available": boolean;
958
- "default": boolean;
959
- "harness": "pi" | "google" | "systemone";
960
- "efforts"?: Array<"off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max">;
961
- "decision"?: {
962
- "endpoint": "/v1/decisions";
963
- "question_types": Array<"noul" | "choice" | "score">;
964
- };
965
- }>;
966
- /** Opaque keyset cursor; null on the last page. */
967
- "next_cursor": string | null;
968
- }
969
- export interface WireToolList {
970
- "object": "list";
971
- "data": Array<{
972
- "type": "web_search" | "fetch_content" | "hublu" | "memory" | "image" | "browser" | "android";
973
- "object": "tool";
974
- "description": string;
975
- "expands_to": string[];
976
- "available": boolean;
977
- }>;
978
- /** Opaque keyset cursor; null on the last page. */
979
- "next_cursor": string | null;
980
- }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,3 @@
1
- import type { WireBriefPublishInput, WireBriefPublishResult, WireBriefDetail } from "./generated.js";
2
- export type { WireBriefPublishInput, WireBriefPublishResult, WireBriefDetail } from "./generated.js";
3
- export type { WireBriefPublishInput as BriefPublishInput, WireBriefPublishResult as BriefPublishResult, WireBriefDetail as BriefDetail } from "./generated.js";
4
1
  /**
5
2
  * @betterlu/agentlu - client for the agentlu service API.
6
3
  *
@@ -12,13 +9,10 @@ export type { WireBriefPublishInput as BriefPublishInput, WireBriefPublishResult
12
9
  * get-or-create registration, typed `runJson` / `runText`, use-case catalogs,
13
10
  * background `wait`, and auto-retry on `409 thread_busy`.
14
11
  *
15
- * Two tiers, two namespaces (1.8):
16
- *
17
- * - `alu.llm.text/json/stream(...)` - the direct tier: one profile-free
18
- * provider call, no tools, no session.
19
- * - `alu.agent.run/stream/background(...)` - the agent tier: a profile,
12
+ * The agent tier is exposed through `alu.agent.run/stream/background(...)`:
13
+ * a profile,
20
14
  * tool families, threads and background runs.
21
- * - `alu.run/runJson/runText/stream` stay as aliases of the agent tier.
15
+ * `alu.run/runJson/runText/stream` stay as aliases of the agent tier.
22
16
  *
23
17
  * Errors carry a coarse `kind` (`unavailable | timeout | rate_limited |
24
18
  * invalid_request | schema | incomplete | internal`) and `isUnavailable(err)`
@@ -28,7 +22,7 @@ export type { WireBriefPublishInput as BriefPublishInput, WireBriefPublishResult
28
22
  * `Wire*` types (see `generated.ts`, regenerate with `npm run gen:contract`).
29
23
  */
30
24
  import type { WireHouseholdSignalInput, WireHouseholdSignalResult, WireAppAgentDeclaration, WireClientDefaults, WireUseCaseProfile } from "./generated.js";
31
- export type { WireHouseholdSignalInput, WireHouseholdSignalResult, WireAppAgentDeclaration, WireAgentInfo, WireChatCompletion, WireChatCompletionRequest, WireClient, WireClientDefaults, WireCreateDecision, WireCreateResponse, WireCreateThreadRequest, WireDecision, WireError, WireFile, WireModelInfo, WireRegisterClientRequest, WireResponse, WireStreamEvent, WireThread, WireThreadMessage, WireToolInfo, WireUseCaseProfile, } from "./generated.js";
25
+ export type { WireHouseholdSignalInput, WireHouseholdSignalResult, WireAppAgentDeclaration, WireChatCompletion, WireChatCompletionRequest, WireClient, WireClientDefaults, WireCreateDecision, WireCreateResponse, WireCreateThreadRequest, WireDecision, WireError, WireFile, WireRegisterClientRequest, WireResponse, WireStreamEvent, WireThread, WireThreadMessage, WireUseCaseProfile, } from "./generated.js";
32
26
  export declare const DEFAULT_BASE_URL = "http://localhost:8912/v1";
33
27
  /**
34
28
  * Accept an origin (`http://host:8912`) or a `/v1` base and normalize to the
@@ -428,40 +422,6 @@ export interface UploadManyOptions extends UploadOptions {
428
422
  /** Parallel uploads. Default 3. */
429
423
  concurrency?: number;
430
424
  }
431
- /**
432
- * Direct-tier request (`llm.text` / `llm.json` / `llm.stream`): one
433
- * profile-free provider call, no tools, no session. `instructions` is the
434
- * whole system prompt.
435
- */
436
- export interface LlmRequest {
437
- input: string;
438
- instructions?: string;
439
- model?: string;
440
- temperature?: number;
441
- timeoutMs?: number;
442
- maxOutputTokens?: number;
443
- metadata?: Record<string, string>;
444
- signal?: AbortSignal;
445
- maxAttempts?: number;
446
- idempotencyKey?: string;
447
- }
448
- export interface LlmJsonRequest extends LlmRequest {
449
- /** Format name sent to the provider (default "Result"). */
450
- schemaName?: string;
451
- }
452
- export interface LlmApi {
453
- text: (request: string | LlmRequest) => Promise<{
454
- text: string;
455
- response: ResponseObject;
456
- }>;
457
- json: <T = unknown>(schema: Record<string, unknown>, request: string | LlmJsonRequest) => Promise<{
458
- data: T;
459
- response: ResponseObject;
460
- }>;
461
- stream: (request: string | LlmRequest) => AsyncIterable<StreamEvent> & {
462
- finalText: () => Promise<string>;
463
- };
464
- }
465
425
  /** Agent-tier entry points (`alu.agent.*`). */
466
426
  export interface AgentTierApi {
467
427
  run: (opts: RunOptions) => Promise<{
@@ -502,30 +462,6 @@ export interface ResponseObject {
502
462
  [k: string]: unknown;
503
463
  }
504
464
  export declare function isTerminalStatus(status: string): boolean;
505
- /**
506
- * One SSE event from `/v1/responses` with `stream: true`. The event names and
507
- * shapes mirror the OpenAI Responses stream; `delta` is the incremental text
508
- * for `response.output_text.delta`.
509
- */
510
- export interface StreamEvent {
511
- type: string;
512
- sequence_number?: number;
513
- /** Incremental text on `response.output_text.delta`. */
514
- delta?: string;
515
- [k: string]: unknown;
516
- }
517
- /**
518
- * Accumulate a raw stream into typed events and the final text. `events()`
519
- * yields every event; `finalText()` resolves after the stream ends with the
520
- * concatenated `response.output_text.delta` payloads.
521
- *
522
- * const stream = alu.typedStream({ input: "hi" });
523
- * for await (const ev of stream) { ... }
524
- * const text = stream.finalText();
525
- */
526
- export declare function typedStream(source: AsyncIterable<Record<string, unknown>>): AsyncIterable<StreamEvent> & {
527
- finalText: () => Promise<string>;
528
- };
529
465
  export declare class AgentLu {
530
466
  readonly baseUrl: string;
531
467
  apiKey: string | undefined;
@@ -571,7 +507,6 @@ export declare class AgentLu {
571
507
  kind?: string;
572
508
  }>;
573
509
  private uploadForApiKey;
574
- me(): Promise<unknown>;
575
510
  /**
576
511
  * One-shot helper. When `schema` is given, returns the validated object as
577
512
  * `data` and throws `AgentLuError("schema_validation_failed")` if the server
@@ -597,30 +532,12 @@ export declare class AgentLu {
597
532
  /** `runText` that returns `null` instead of throwing on any failure. */
598
533
  runTextOrNull(opts: RunOptions): Promise<string | null>;
599
534
  stream(opts: RunOptions): AsyncGenerator<Record<string, unknown>>;
600
- /**
601
- * Typed stream: yields `StreamEvent`s and exposes `finalText()` with the
602
- * concatenated output text after the stream ends.
603
- */
604
- typedStream(opts: RunOptions): AsyncIterable<StreamEvent> & {
605
- finalText: () => Promise<string>;
606
- };
607
- /**
608
- * Direct tier (`agent: "direct"`): one profile-free provider call - no
609
- * profile, no tools, no session. Use it for extraction, classification and
610
- * short answers; use `agent.*` when the run needs tools or a thread.
611
- *
612
- * const { text } = await alu.llm.text("Name three colours.");
613
- * const { data } = await alu.llm.json(schema, { input, schemaName: "Items" });
614
- */
615
- readonly llm: LlmApi;
616
535
  /**
617
536
  * Agent tier: a profile, tool families, threads and background runs. The
618
537
  * default agent is `api` (no persona - `instructions` are the system prompt);
619
538
  * pin `fast`/`thorough`/... or an app-owned `<app>/<name>` id when needed.
620
539
  */
621
540
  readonly agent: AgentTierApi;
622
- /** Build a direct-tier run body from a short-form `llm.*` request. */
623
- private llmOptions;
624
541
  /**
625
542
  * Enqueue a background run (`background: true`) and poll it to a terminal
626
543
  * status with `responses.wait`. Resolves with the terminal Response row -
@@ -671,10 +588,6 @@ export declare class AgentLu {
671
588
  delete: (id: string) => Promise<unknown>;
672
589
  messages: (id: string) => Promise<unknown>;
673
590
  };
674
- readonly briefs: {
675
- publish: (input: WireBriefPublishInput, opts?: RequestOptions) => Promise<WireBriefPublishResult>;
676
- get: (id: string, opts?: RequestOptions) => Promise<WireBriefDetail>;
677
- };
678
591
  readonly household: {
679
592
  signal: (input: WireHouseholdSignalInput, opts?: RequestOptions) => Promise<WireHouseholdSignalResult>;
680
593
  };
@@ -695,10 +608,6 @@ export declare class AgentLu {
695
608
  * overrides the shared 5-attempt policy, and `signal` cancels the call.
696
609
  */
697
610
  readonly decisions: DecisionApi;
698
- agents(): Promise<unknown>;
699
- models(): Promise<unknown>;
700
- tools(): Promise<unknown>;
701
- health(): Promise<unknown>;
702
611
  /**
703
612
  * Wait until the service answers `/health`, retrying while it is unreachable
704
613
  * (offline, 502/503/504, timeout) with jittered backoff. Resolves `true` once
@@ -767,10 +676,6 @@ export declare class UseCaseRunner {
767
676
  /** `runText` that returns `null` instead of throwing on any failure. */
768
677
  runTextOrNull(opts: RunOptions): Promise<string | null>;
769
678
  stream(opts: RunOptions): AsyncGenerator<Record<string, unknown>>;
770
- /** Typed stream for this use-case: events + `finalText()`. */
771
- typedStream(opts: RunOptions): AsyncIterable<StreamEvent> & {
772
- finalText: () => Promise<string>;
773
- };
774
679
  /**
775
680
  * Upload with this use-case's key, so the file is owned by the same
776
681
  * service client that will reference it via `run({ fileIds })`.
package/dist/index.js CHANGED
@@ -1,6 +1,4 @@
1
1
  export const DEFAULT_BASE_URL = "http://localhost:8912/v1";
2
- /** Wire agent id for the direct tier (not a chat mode). */
3
- const DIRECT_AGENT_ID = "direct";
4
2
  /** Default agent for the agent tier: the profile-free machine agent. */
5
3
  const AGENT_TIER_AGENT = "api";
6
4
  /**
@@ -193,44 +191,6 @@ async function uploadManyWith(files, opts, upload) {
193
191
  export function isTerminalStatus(status) {
194
192
  return status === "completed" || status === "failed" || status === "incomplete" || status === "cancelled";
195
193
  }
196
- /**
197
- * Accumulate a raw stream into typed events and the final text. `events()`
198
- * yields every event; `finalText()` resolves after the stream ends with the
199
- * concatenated `response.output_text.delta` payloads.
200
- *
201
- * const stream = alu.typedStream({ input: "hi" });
202
- * for await (const ev of stream) { ... }
203
- * const text = stream.finalText();
204
- */
205
- export function typedStream(source) {
206
- let text = "";
207
- let done = false;
208
- const it = (async function* () {
209
- try {
210
- for await (const raw of source) {
211
- const ev = raw;
212
- if (ev.type === "response.output_text.delta" && typeof ev.delta === "string") {
213
- text += ev.delta;
214
- }
215
- yield ev;
216
- }
217
- }
218
- finally {
219
- done = true;
220
- }
221
- })();
222
- return Object.assign(it, {
223
- finalText: async () => {
224
- // Drain if the caller never iterated to the end.
225
- if (!done) {
226
- for await (const _ of it) {
227
- void _;
228
- }
229
- }
230
- return text;
231
- },
232
- });
233
- }
234
194
  function env(name) {
235
195
  return typeof process !== "undefined" ? process.env[name] : undefined;
236
196
  }
@@ -361,9 +321,6 @@ export class AgentLu {
361
321
  });
362
322
  return (await res.json());
363
323
  }
364
- async me() {
365
- return this.request("GET", "/me");
366
- }
367
324
  /**
368
325
  * One-shot helper. When `schema` is given, returns the validated object as
369
326
  * `data` and throws `AgentLuError("schema_validation_failed")` if the server
@@ -405,29 +362,6 @@ export class AgentLu {
405
362
  async *stream(opts) {
406
363
  yield* this.streamRunForApiKey(opts, this.apiKey);
407
364
  }
408
- /**
409
- * Typed stream: yields `StreamEvent`s and exposes `finalText()` with the
410
- * concatenated output text after the stream ends.
411
- */
412
- typedStream(opts) {
413
- return typedStream(this.stream(opts));
414
- }
415
- /**
416
- * Direct tier (`agent: "direct"`): one profile-free provider call - no
417
- * profile, no tools, no session. Use it for extraction, classification and
418
- * short answers; use `agent.*` when the run needs tools or a thread.
419
- *
420
- * const { text } = await alu.llm.text("Name three colours.");
421
- * const { data } = await alu.llm.json(schema, { input, schemaName: "Items" });
422
- */
423
- llm = {
424
- text: (request) => this.runText(this.llmOptions(request)),
425
- json: (schema, request) => {
426
- const schemaName = typeof request === "string" ? undefined : request.schemaName;
427
- return this.runJson({ ...this.llmOptions(request), schema, schemaName: schemaName ?? "Result" });
428
- },
429
- stream: (request) => this.typedStream(this.llmOptions(request)),
430
- };
431
365
  /**
432
366
  * Agent tier: a profile, tool families, threads and background runs. The
433
367
  * default agent is `api` (no persona - `instructions` are the system prompt);
@@ -438,11 +372,6 @@ export class AgentLu {
438
372
  stream: (opts) => this.stream(withAgentTierDefault(opts)),
439
373
  background: (opts, wait) => this.runBackground(withAgentTierDefault(opts), wait),
440
374
  };
441
- /** Build a direct-tier run body from a short-form `llm.*` request. */
442
- llmOptions(request) {
443
- const opts = typeof request === "string" ? { input: request } : request;
444
- return { ...opts, agent: DIRECT_AGENT_ID, store: false, tools: [] };
445
- }
446
375
  /**
447
376
  * Enqueue a background run (`background: true`) and poll it to a terminal
448
377
  * status with `responses.wait`. Resolves with the terminal Response row -
@@ -728,10 +657,6 @@ export class AgentLu {
728
657
  delete: (id) => this.request("DELETE", `/threads/${encodeURIComponent(id)}`),
729
658
  messages: (id) => this.request("GET", `/threads/${encodeURIComponent(id)}/messages`),
730
659
  };
731
- briefs = {
732
- publish: (input, opts) => this.request("POST", "/briefs", input, opts),
733
- get: (id, opts) => this.request("GET", `/briefs/${encodeURIComponent(id)}`, undefined, opts),
734
- };
735
660
  household = {
736
661
  signal: (input, opts) => this.request("POST", "/household/signals", input, opts),
737
662
  };
@@ -763,18 +688,6 @@ export class AgentLu {
763
688
  }
764
689
  },
765
690
  };
766
- async agents() {
767
- return this.request("GET", "/agents", undefined, { auth: false });
768
- }
769
- async models() {
770
- return this.request("GET", "/models", undefined, { auth: false });
771
- }
772
- async tools() {
773
- return this.request("GET", "/tools", undefined, { auth: false });
774
- }
775
- async health() {
776
- return this.request("GET", "/health", undefined, { auth: false });
777
- }
778
691
  /**
779
692
  * Wait until the service answers `/health`, retrying while it is unreachable
780
693
  * (offline, 502/503/504, timeout) with jittered backoff. Resolves `true` once
@@ -1017,10 +930,6 @@ export class UseCaseRunner {
1017
930
  yield* this.operations.stream(this.apiKey, opts);
1018
931
  }
1019
932
  }
1020
- /** Typed stream for this use-case: events + `finalText()`. */
1021
- typedStream(opts) {
1022
- return typedStream(this.stream(opts));
1023
- }
1024
933
  /**
1025
934
  * Upload with this use-case's key, so the file is owned by the same
1026
935
  * service client that will reference it via `run({ fileIds })`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@betterlu/agentlu",
3
- "version": "1.11.0",
3
+ "version": "2.0.0",
4
4
  "description": "Client for the agentlu service API (/v1). Or just use the openai SDK pointed at http://localhost:8912/v1.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",