@alfe.ai/claude-code-host 0.1.14 → 0.1.16
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/cli.js +1 -1
- package/dist/host-config.cjs +1592 -96
- package/dist/host-config.js +1444 -98
- package/dist/index.cjs +25 -0
- package/dist/index.d.cts +535 -46
- package/dist/index.d.ts +535 -46
- package/dist/index.js +2 -2
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -849,6 +849,43 @@ interface AgentWorkspaceInfo {
|
|
|
849
849
|
teamIds?: string[];
|
|
850
850
|
projectIds?: string[];
|
|
851
851
|
}
|
|
852
|
+
/**
|
|
853
|
+
* The agent's own Claude credential (claude-code runtime), from
|
|
854
|
+
* GET /agent/claude-credential. `oauth_token` is a Claude subscription token
|
|
855
|
+
* (`claude setup-token`) for `CLAUDE_CODE_OAUTH_TOKEN`; `api_key` is an
|
|
856
|
+
* Anthropic API key for `ANTHROPIC_API_KEY`. `revision` changes on every
|
|
857
|
+
* dashboard write. Hold the value in memory only — never log or persist it.
|
|
858
|
+
*/
|
|
859
|
+
interface AgentClaudeCredential {
|
|
860
|
+
kind: "oauth_token" | "api_key";
|
|
861
|
+
value: string;
|
|
862
|
+
revision: string;
|
|
863
|
+
updatedAt: string;
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Claude auth health a claude-code host reports for its agent. `missing` is
|
|
867
|
+
* legacy: hosts since the AI-proxy fallback (2026-10-15) never send it.
|
|
868
|
+
*/
|
|
869
|
+
type ClaudeCredentialHealth = "ok" | "missing" | "invalid";
|
|
870
|
+
/**
|
|
871
|
+
* Which auth the host's turns run on: the stored credential, the machine's
|
|
872
|
+
* own `claude` login (self-hosted only), or the Alfe AI proxy (Alfe credits).
|
|
873
|
+
*/
|
|
874
|
+
type ClaudeCredentialSource = "credential" | "local_login" | "ai_proxy";
|
|
875
|
+
/** Body of PUT /agent/claude-credential/status. */
|
|
876
|
+
interface ClaudeCredentialStatusReport {
|
|
877
|
+
status: ClaudeCredentialHealth;
|
|
878
|
+
/** The auth source the status describes. Omitted only by older hosts. */
|
|
879
|
+
source?: ClaudeCredentialSource;
|
|
880
|
+
/** Short (≤200 chars), fixed host-side explanation. Never `claude` output or a secret. */
|
|
881
|
+
detail?: string;
|
|
882
|
+
/**
|
|
883
|
+
* The credential revision the host checked (from `getClaudeCredential()`);
|
|
884
|
+
* omit when it found none. The server drops reports for a superseded
|
|
885
|
+
* revision and answers `{ accepted: false }`.
|
|
886
|
+
*/
|
|
887
|
+
revision?: string;
|
|
888
|
+
}
|
|
852
889
|
declare class WorkspaceApi extends ApiBase {
|
|
853
890
|
/**
|
|
854
891
|
* GET /agent/workspace — workspace config for the authenticated agent
|
|
@@ -865,6 +902,22 @@ declare class WorkspaceApi extends ApiBase {
|
|
|
865
902
|
}): Promise<{
|
|
866
903
|
files: Record<string, string>;
|
|
867
904
|
}>;
|
|
905
|
+
/**
|
|
906
|
+
* GET /agent/claude-credential — the authenticated claude-code agent's own
|
|
907
|
+
* Claude credential, or `null` when none is stored (the host then falls back
|
|
908
|
+
* to the local `claude` login when self-hosted, else the Alfe AI proxy). Fetch on every runtime start: the
|
|
909
|
+
* daemon restarts the host whenever the credential changes.
|
|
910
|
+
*/
|
|
911
|
+
getClaudeCredential(): Promise<AgentClaudeCredential | null>;
|
|
912
|
+
/**
|
|
913
|
+
* PUT /agent/claude-credential/status — report whether this claude-code agent
|
|
914
|
+
* can authenticate to Claude. `accepted: false` means the report described a
|
|
915
|
+
* credential that has since been replaced; nothing was written. Not retried
|
|
916
|
+
* automatically (a mutation): the host re-reports on its next signal.
|
|
917
|
+
*/
|
|
918
|
+
reportClaudeCredentialStatus(report: ClaudeCredentialStatusReport): Promise<{
|
|
919
|
+
accepted: boolean;
|
|
920
|
+
}>;
|
|
868
921
|
}
|
|
869
922
|
//# sourceMappingURL=workspace.d.ts.map
|
|
870
923
|
//#endregion
|
|
@@ -2224,6 +2277,131 @@ declare class ChatServiceClient {
|
|
|
2224
2277
|
* Resolution priority: explicit overrides → config file → env vars.
|
|
2225
2278
|
*/
|
|
2226
2279
|
//#endregion
|
|
2280
|
+
//#region src/child-env.d.ts
|
|
2281
|
+
/**
|
|
2282
|
+
* Child-process environment construction for spawned `claude` CLI processes.
|
|
2283
|
+
*
|
|
2284
|
+
* Every turn runs on exactly ONE auth source (`ChildAuth`), resolved by the
|
|
2285
|
+
* host (see DEVELOPING.md "Auth source resolution"):
|
|
2286
|
+
*
|
|
2287
|
+
* - `credential` — the agent's stored Claude credential, set as exactly one
|
|
2288
|
+
* variable: `CLAUDE_CODE_OAUTH_TOKEN` (subscription token from
|
|
2289
|
+
* `claude setup-token`) or `ANTHROPIC_API_KEY` (Anthropic API key).
|
|
2290
|
+
* - `local_login` — self-hosted only: no auth variable, so `claude` uses the
|
|
2291
|
+
* machine's own login (and whatever provider the operator configured).
|
|
2292
|
+
* - `ai_proxy` — the Alfe AI proxy via the daemon's loopback proxy:
|
|
2293
|
+
* `ANTHROPIC_BASE_URL` = the local proxy, `ANTHROPIC_AUTH_TOKEN` = a
|
|
2294
|
+
* placeholder the local proxy replaces with the daemon's agent key, and
|
|
2295
|
+
* every model alias pinned to an Alfe registry id (the proxy routes exact
|
|
2296
|
+
* registry ids only; the CLI's built-in aliases resolve to dated ids that
|
|
2297
|
+
* are a 409 there).
|
|
2298
|
+
*
|
|
2299
|
+
* Invariants:
|
|
2300
|
+
*
|
|
2301
|
+
* 1. **Scrub inherited Claude auth.** `ANTHROPIC_API_KEY` / `ANTHROPIC_BASE_URL`
|
|
2302
|
+
* / `ANTHROPIC_AUTH_TOKEN` / `CLAUDE_CODE_OAUTH_TOKEN` are removed from BOTH
|
|
2303
|
+
* the parent env and any caller `extra`. A self-hosted Mac very often has
|
|
2304
|
+
* these set for other tooling; if one reaches `claude` it silently switches
|
|
2305
|
+
* accounts or billing plane. Credential and proxy modes also drop provider
|
|
2306
|
+
* overrides (Bedrock/Vertex/Foundry); proxy mode additionally drops model
|
|
2307
|
+
* and header overrides so nothing reaches the proxy that it cannot price.
|
|
2308
|
+
*
|
|
2309
|
+
* 2. **Inject the source last.** Nothing in `base` or `extra` can override the
|
|
2310
|
+
* injected credential or proxy settings. A credential lives only in the
|
|
2311
|
+
* host's memory and this env, never on disk, never logged. Proxy settings
|
|
2312
|
+
* never appear in a credential or local-login env.
|
|
2313
|
+
*
|
|
2314
|
+
* 3. **Set `ALFE_CLAUDE_BRIDGE=1`.** The Phase-1 CLI hooks
|
|
2315
|
+
* (`alfe claude hook ...` in `packages/cli/src/commands/claude.ts`) check
|
|
2316
|
+
* `process.env.ALFE_CLAUDE_BRIDGE` FIRST and no-op when set, so the host —
|
|
2317
|
+
* not the interactive-session hooks — owns memory recall/capture for bridged
|
|
2318
|
+
* turns. Omitting this double-captures every message. The env var NAME is a
|
|
2319
|
+
* cross-phase contract; do not rename without updating the CLI.
|
|
2320
|
+
*/
|
|
2321
|
+
/** Claude auth env vars that MUST NOT be inherited by a `claude` child. */
|
|
2322
|
+
declare const SCRUBBED_ANTHROPIC_ENV_VARS: readonly ["ANTHROPIC_API_KEY", "ANTHROPIC_BASE_URL", "ANTHROPIC_AUTH_TOKEN", "CLAUDE_CODE_OAUTH_TOKEN"];
|
|
2323
|
+
/**
|
|
2324
|
+
* Provider-selection and endpoint overrides that would route `claude` away from
|
|
2325
|
+
* the Anthropic API. Dropped whenever a credential or the AI proxy is in use,
|
|
2326
|
+
* so an inherited `CLAUDE_CODE_USE_BEDROCK=1` (say) can't send the turn to
|
|
2327
|
+
* Bedrock and ignore the chosen source. On a local login they are left alone:
|
|
2328
|
+
* the machine's own `claude` setup is the source, whatever provider it uses.
|
|
2329
|
+
*/
|
|
2330
|
+
|
|
2331
|
+
/** Cross-phase contract marker (see header + packages/cli/src/commands/claude.ts). */
|
|
2332
|
+
declare const BRIDGE_ENV_VAR = "ALFE_CLAUDE_BRIDGE";
|
|
2333
|
+
/**
|
|
2334
|
+
* Placeholder `ANTHROPIC_AUTH_TOKEN` (sent as `Authorization: Bearer`) for
|
|
2335
|
+
* proxy mode. `@alfe.ai/ai-proxy-local` keeps an incoming `alfe_…` key and
|
|
2336
|
+
* replaces anything else with the daemon's agent key (as `x-api-key`, dropping
|
|
2337
|
+
* `authorization`), so the agent key itself never enters the `claude` env (a
|
|
2338
|
+
* managed agent has Bash). Never `alfe_…`.
|
|
2339
|
+
*/
|
|
2340
|
+
declare const PROXY_API_KEY_PLACEHOLDER = "alfe-local-proxy";
|
|
2341
|
+
/**
|
|
2342
|
+
* Default local AI proxy (`DEFAULT_AI_PROXY_PORT` in `@alfe.ai/ai-proxy-local`).
|
|
2343
|
+
* The daemon passes the URL it actually bound as `ALFE_LOCAL_AI_PROXY_URL`;
|
|
2344
|
+
* this is the fallback. Bare host, no `/v1`: `claude` appends `/v1/messages`.
|
|
2345
|
+
*/
|
|
2346
|
+
declare const DEFAULT_LOCAL_AI_PROXY_URL = "http://127.0.0.1:18193";
|
|
2347
|
+
/**
|
|
2348
|
+
* The model `claude -p --model` runs in proxy mode when the agent has no
|
|
2349
|
+
* `defaultModel` (or the daemon's lookup timed out). `claude`'s own default is
|
|
2350
|
+
* a dated id the proxy cannot route. Haiku 4.5 is the one Claude model seeded
|
|
2351
|
+
* on every stage (the memory integration depends on it), so it is the only
|
|
2352
|
+
* id guaranteed to route; the dashboard always sets a model, so this is rare.
|
|
2353
|
+
*/
|
|
2354
|
+
declare const PROXY_DEFAULT_MODEL = "claude-haiku-4-5";
|
|
2355
|
+
/**
|
|
2356
|
+
* Fixed model env in proxy mode, Alfe registry ids (`AnthropicModel` in
|
|
2357
|
+
* `@alfe/types`; the child-env test asserts it). `ANTHROPIC_SMALL_FAST_MODEL`
|
|
2358
|
+
* drives background calls (titles, summaries); `ANTHROPIC_DEFAULT_HAIKU_MODEL`
|
|
2359
|
+
* resolves the `haiku` alias. Haiku 4.5 because it is seeded on every stage.
|
|
2360
|
+
* claude 2.1.284/2.1.287 read these and {@link PROXY_AGENT_MODEL_ENV_VARS}.
|
|
2361
|
+
*/
|
|
2362
|
+
declare const PROXY_MODEL_ENV: {
|
|
2363
|
+
readonly ANTHROPIC_SMALL_FAST_MODEL: "claude-haiku-4-5";
|
|
2364
|
+
readonly ANTHROPIC_DEFAULT_HAIKU_MODEL: "claude-haiku-4-5";
|
|
2365
|
+
};
|
|
2366
|
+
/**
|
|
2367
|
+
* The `sonnet` / `opus` aliases (subagents) resolve to the agent's OWN model
|
|
2368
|
+
* in proxy mode: the agents service validated it against the registry, while a
|
|
2369
|
+
* fixed 5.x id may not be enabled on the workspace.
|
|
2370
|
+
*/
|
|
2371
|
+
declare const PROXY_AGENT_MODEL_ENV_VARS: readonly ["ANTHROPIC_DEFAULT_SONNET_MODEL", "ANTHROPIC_DEFAULT_OPUS_MODEL"];
|
|
2372
|
+
/** Set only in proxy mode (besides the auth pair). */
|
|
2373
|
+
|
|
2374
|
+
/** The agent's Claude credential, as fetched from `GET /agent/claude-credential`. */
|
|
2375
|
+
interface ChildCredential {
|
|
2376
|
+
kind: 'oauth_token' | 'api_key';
|
|
2377
|
+
value: string;
|
|
2378
|
+
}
|
|
2379
|
+
/** The single env var each credential kind is exported as. */
|
|
2380
|
+
declare const CREDENTIAL_ENV_VAR: Record<ChildCredential['kind'], string>;
|
|
2381
|
+
/** The auth source of one `claude` child. */
|
|
2382
|
+
type ChildAuth = {
|
|
2383
|
+
mode: 'credential';
|
|
2384
|
+
credential: ChildCredential;
|
|
2385
|
+
} | {
|
|
2386
|
+
mode: 'local_login';
|
|
2387
|
+
}
|
|
2388
|
+
/** `model` = the turn's registry model id (`--model`); also the sonnet/opus aliases. */ | {
|
|
2389
|
+
mode: 'ai_proxy';
|
|
2390
|
+
baseUrl: string;
|
|
2391
|
+
model: string;
|
|
2392
|
+
};
|
|
2393
|
+
/**
|
|
2394
|
+
* Build the env handed to a spawned `claude` child. Pure — takes the base env
|
|
2395
|
+
* explicitly so it unit-tests without touching `process.env`.
|
|
2396
|
+
*
|
|
2397
|
+
* Order: merge `base` + `extra` → drop every scrubbed var (plus provider
|
|
2398
|
+
* overrides for a credential or the proxy, plus model overrides for the
|
|
2399
|
+
* proxy) → set the bridge marker → set the source's variables. Neither `base`
|
|
2400
|
+
* nor `extra` can smuggle an auth variable in or override the source.
|
|
2401
|
+
* `auth` omitted = local login.
|
|
2402
|
+
*/
|
|
2403
|
+
declare function buildChildEnv(base: NodeJS.ProcessEnv, extra?: Record<string, string>, auth?: ChildAuth): NodeJS.ProcessEnv;
|
|
2404
|
+
//#endregion
|
|
2227
2405
|
//#region src/stream-mapper.d.ts
|
|
2228
2406
|
/**
|
|
2229
2407
|
* Claude Code `--output-format stream-json` → Alfe chat-activity mapper.
|
|
@@ -2314,6 +2492,17 @@ interface EndEmission {
|
|
|
2314
2492
|
durationMs?: number;
|
|
2315
2493
|
/** Error reason (present when `isError`). Goes under `payload.message` (C3). */
|
|
2316
2494
|
errorMessage?: string;
|
|
2495
|
+
/**
|
|
2496
|
+
* True when Claude refused the credential (assistant `error:
|
|
2497
|
+
* "authentication_failed"`, a 401/403 `api_error_status`, or a known auth
|
|
2498
|
+
* message). Present only on error turns.
|
|
2499
|
+
*/
|
|
2500
|
+
authFailed?: true;
|
|
2501
|
+
/**
|
|
2502
|
+
* The refusal was a 403 (forbidden: an org or provider policy), not a dead
|
|
2503
|
+
* login or key. Present only with `authFailed`.
|
|
2504
|
+
*/
|
|
2505
|
+
authForbidden?: true;
|
|
2317
2506
|
}
|
|
2318
2507
|
type MapperEmission = ActivityEmission | TextEmission | EndEmission;
|
|
2319
2508
|
interface PendingTool {
|
|
@@ -2333,6 +2522,8 @@ interface MapperState {
|
|
|
2333
2522
|
pendingTools: Map<string, PendingTool>;
|
|
2334
2523
|
/** Whether the terminal `result` event has been seen. */
|
|
2335
2524
|
ended: boolean;
|
|
2525
|
+
/** Set by an assistant `error: "authentication_failed"` frame. */
|
|
2526
|
+
authFailed: boolean;
|
|
2336
2527
|
}
|
|
2337
2528
|
declare function createMapperState(): MapperState;
|
|
2338
2529
|
/**
|
|
@@ -2382,6 +2573,26 @@ declare const WARM_STREAMING_SUPPORTED = false;
|
|
|
2382
2573
|
* shell. Callers that want a wider set pass `allowedTools` explicitly.
|
|
2383
2574
|
*/
|
|
2384
2575
|
declare const DEFAULT_ALLOWED_TOOLS: readonly ["Read", "Grep", "Glob", "LS", "Edit", "Write", "WebFetch", "WebSearch", "Task", "TodoWrite"];
|
|
2576
|
+
/**
|
|
2577
|
+
* Managed VMs (`ALFE_MANAGED=1|true`) add `Bash` to the allow-list. The VM is
|
|
2578
|
+
* the agent's own machine (no user data beside the agent's workspace), and
|
|
2579
|
+
* shell access is what makes a managed coding agent useful. Still
|
|
2580
|
+
* `--permission-mode dontAsk` (never bypass), and the managed VM runs as root:
|
|
2581
|
+
* claude refuses only `--dangerously-skip-permissions` under root, not
|
|
2582
|
+
* `dontAsk`. `Edit`/`Write` are already in the default set; `MultiEdit` is not
|
|
2583
|
+
* a tool in the pinned claude (2.1.x), so it is not listed.
|
|
2584
|
+
*/
|
|
2585
|
+
declare const MANAGED_ALLOWED_TOOLS: readonly ["Read", "Grep", "Glob", "LS", "Edit", "Write", "WebFetch", "WebSearch", "Task", "TodoWrite", "Bash"];
|
|
2586
|
+
/**
|
|
2587
|
+
* Deny rules layered on the managed allow-list (`--disallowedTools`, which
|
|
2588
|
+
* wins over `--allowedTools`). They keep the agent from re-running Google
|
|
2589
|
+
* Workspace CLI auth and from reading its token directory with the Read tool.
|
|
2590
|
+
* They are NOT a security boundary: with Bash allowed, `cat`, `cp`, `env` and
|
|
2591
|
+
* friends can still read anything the root user can. Verified on claude
|
|
2592
|
+
* 2.1.284: a `Bash(<prefix>:*)` rule denies the matching command under
|
|
2593
|
+
* `dontAsk` while other Bash commands run.
|
|
2594
|
+
*/
|
|
2595
|
+
declare const MANAGED_DISALLOWED_TOOLS: readonly ["Bash(gws auth)", "Bash(gws auth:*)", "Read(~/.config/gws-*/**)"];
|
|
2385
2596
|
declare const CLAUDE_PERMISSION_MODES: readonly ["acceptEdits", "auto", "manual", "dontAsk", "plan"];
|
|
2386
2597
|
type ClaudePermissionMode = (typeof CLAUDE_PERMISSION_MODES)[number];
|
|
2387
2598
|
/**
|
|
@@ -2404,6 +2615,10 @@ interface DriverTurnResult {
|
|
|
2404
2615
|
errorMessage?: string;
|
|
2405
2616
|
/** True if the turn was aborted via `abort()` (SIGINT). */
|
|
2406
2617
|
aborted: boolean;
|
|
2618
|
+
/** Present (true) when the turn failed because Claude refused the credential. */
|
|
2619
|
+
authFailed?: true;
|
|
2620
|
+
/** With `authFailed`: the refusal was a 403 (policy), not a dead login/key. */
|
|
2621
|
+
authForbidden?: true;
|
|
2407
2622
|
}
|
|
2408
2623
|
interface RunTurnParams {
|
|
2409
2624
|
/** The user prompt for this turn. */
|
|
@@ -2416,7 +2631,10 @@ interface RunTurnParams {
|
|
|
2416
2631
|
mcpConfigPath?: string;
|
|
2417
2632
|
/** Persona + reply-style text appended to the system prompt. Omitted → none. */
|
|
2418
2633
|
appendSystemPrompt?: string;
|
|
2419
|
-
/**
|
|
2634
|
+
/**
|
|
2635
|
+
* Bare Claude model id for `--model`. Omitted → CLI default (never in proxy
|
|
2636
|
+
* mode: the host always passes a registry id there).
|
|
2637
|
+
*/
|
|
2420
2638
|
model?: string;
|
|
2421
2639
|
/** Tool allow-list (defaults to DEFAULT_ALLOWED_TOOLS). */
|
|
2422
2640
|
allowedTools?: readonly string[];
|
|
@@ -2449,12 +2667,21 @@ declare class SessionDriver {
|
|
|
2449
2667
|
private abortCurrent;
|
|
2450
2668
|
private readonly bin;
|
|
2451
2669
|
private readonly baseEnv;
|
|
2670
|
+
private readonly auth;
|
|
2671
|
+
private readonly managed;
|
|
2452
2672
|
private readonly log;
|
|
2453
2673
|
/** Injected spawn — tests replace this with a fake child. */
|
|
2454
2674
|
private readonly spawnImpl;
|
|
2455
2675
|
constructor(opts?: {
|
|
2456
2676
|
claudeBin?: string;
|
|
2457
2677
|
baseEnv?: NodeJS.ProcessEnv;
|
|
2678
|
+
/**
|
|
2679
|
+
* The turn's auth source, applied to the child env after the scrub
|
|
2680
|
+
* (`buildChildEnv`). Absent → the machine's own `claude` login.
|
|
2681
|
+
*/
|
|
2682
|
+
auth?: ChildAuth;
|
|
2683
|
+
/** Managed VM: Bash allowed + deny rules (see MANAGED_ALLOWED_TOOLS). */
|
|
2684
|
+
managed?: boolean;
|
|
2458
2685
|
logger?: Logger;
|
|
2459
2686
|
/** Test seam: inject a fake `spawn`. */
|
|
2460
2687
|
__spawn?: typeof spawn;
|
|
@@ -2475,6 +2702,118 @@ declare class SessionDriver {
|
|
|
2475
2702
|
private runPerTurn;
|
|
2476
2703
|
}
|
|
2477
2704
|
//#endregion
|
|
2705
|
+
//#region src/credential.d.ts
|
|
2706
|
+
interface HostCredential extends ChildCredential {
|
|
2707
|
+
/** Non-secret revision; travels with status reports as the fence. */
|
|
2708
|
+
revision: string;
|
|
2709
|
+
}
|
|
2710
|
+
interface LoadCredentialOptions {
|
|
2711
|
+
/** Aborted on host stop; the loop then resolves `null`. */
|
|
2712
|
+
signal: AbortSignal;
|
|
2713
|
+
log: Logger;
|
|
2714
|
+
baseDelayMs?: number;
|
|
2715
|
+
maxDelayMs?: number;
|
|
2716
|
+
/** Jitter source in [0,1]; the delay is `cap * (0.5 + random/2)`. */
|
|
2717
|
+
random?: () => number;
|
|
2718
|
+
sleep?: (ms: number, signal: AbortSignal) => Promise<void>;
|
|
2719
|
+
}
|
|
2720
|
+
/**
|
|
2721
|
+
* Fetch until it answers. `{ credential: null }` = nothing stored (a real
|
|
2722
|
+
* answer); `null` = aborted before any answer.
|
|
2723
|
+
*/
|
|
2724
|
+
declare function loadCredentialWithRetry(fetchCredential: () => Promise<HostCredential | null>, opts: LoadCredentialOptions): Promise<{
|
|
2725
|
+
credential: HostCredential | null;
|
|
2726
|
+
} | null>;
|
|
2727
|
+
declare function isAuthFailureText(text: string): boolean;
|
|
2728
|
+
/** Why the Alfe AI proxy refused a request it otherwise authenticated. */
|
|
2729
|
+
type ProxyDenial = 'credits' | 'usage_limit' | 'model_unavailable';
|
|
2730
|
+
/**
|
|
2731
|
+
* Classify an Alfe AI proxy refusal from the text `claude` reports. The proxy
|
|
2732
|
+
* answers credit and usage-limit denials on `/v1/messages` with a 429
|
|
2733
|
+
* `rate_limit_error` (never 402, see services/ai DEVELOPING.md "Credit denials
|
|
2734
|
+
* on LLM routes are 429"); claude 2.1.287 surfaces it as
|
|
2735
|
+
* `API Error: Request rejected (429) · <message>` (fixture
|
|
2736
|
+
* `turn-proxy-credits.stream.jsonl`). Credit texts also say "usage limit
|
|
2737
|
+
* reached", so they are checked first. An Anthropic subscription limit
|
|
2738
|
+
* ("Claude AI usage limit reached") is not an Alfe denial.
|
|
2739
|
+
*/
|
|
2740
|
+
declare function classifyProxyDenial(text: string): ProxyDenial | null;
|
|
2741
|
+
/** HTTP statuses on a `result` event that mean "credential refused". */
|
|
2742
|
+
|
|
2743
|
+
type ProbeOutcome = {
|
|
2744
|
+
result: 'ok';
|
|
2745
|
+
}
|
|
2746
|
+
/** `forbidden`: a 403 (an org or provider policy), not a dead login or key. */ | {
|
|
2747
|
+
result: 'invalid';
|
|
2748
|
+
forbidden?: true;
|
|
2749
|
+
}
|
|
2750
|
+
/** The Alfe AI proxy authenticated the agent but refused the request. */ | {
|
|
2751
|
+
result: 'denied';
|
|
2752
|
+
denial: ProxyDenial;
|
|
2753
|
+
} | {
|
|
2754
|
+
result: 'unknown';
|
|
2755
|
+
reason: string;
|
|
2756
|
+
};
|
|
2757
|
+
declare const AUTH_PROBE_TIMEOUT_MS = 60000;
|
|
2758
|
+
/**
|
|
2759
|
+
* argv for the probe. No tools, no session file, no MCP, no settings files.
|
|
2760
|
+
* `model` is `haiku` (the alias) on a credential or local login, and the
|
|
2761
|
+
* registry Haiku id through the AI proxy.
|
|
2762
|
+
*/
|
|
2763
|
+
declare function buildProbeArgs(model?: string): string[];
|
|
2764
|
+
declare function parseProbeOutput(stdout: string, stderr: string, exitCode: number | null): ProbeOutcome;
|
|
2765
|
+
interface AuthProbeOptions {
|
|
2766
|
+
/** The auth source to check (a credential, the local login, or the AI proxy). */
|
|
2767
|
+
auth: ChildAuth;
|
|
2768
|
+
baseEnv: NodeJS.ProcessEnv;
|
|
2769
|
+
/** Any existing directory; the probe reads and writes nothing there. */
|
|
2770
|
+
cwd: string;
|
|
2771
|
+
claudeBin?: string;
|
|
2772
|
+
timeoutMs?: number;
|
|
2773
|
+
spawnImpl?: typeof spawn;
|
|
2774
|
+
/** Host stop: the child is SIGKILLed and the probe settles `unknown`. */
|
|
2775
|
+
signal?: AbortSignal;
|
|
2776
|
+
}
|
|
2777
|
+
/**
|
|
2778
|
+
* One minimal real turn on the given auth source: Anthropic with the agent's
|
|
2779
|
+
* credential or the machine's own login, or the Alfe AI proxy (a Haiku ping
|
|
2780
|
+
* billed from Alfe credits). Never throws.
|
|
2781
|
+
*/
|
|
2782
|
+
declare function runAuthProbe(opts: AuthProbeOptions): Promise<ProbeOutcome>;
|
|
2783
|
+
/** Which auth the host's turns run on (projected as `claudeCredentialSource`). */
|
|
2784
|
+
type CredentialSource = 'credential' | 'local_login' | 'ai_proxy';
|
|
2785
|
+
interface CredentialStatusReport {
|
|
2786
|
+
/** `missing` is legacy; this host never sends it (it falls back to the AI proxy). */
|
|
2787
|
+
status: 'ok' | 'missing' | 'invalid';
|
|
2788
|
+
source?: CredentialSource;
|
|
2789
|
+
/** Fixed, host-authored text only. Never `claude` output. */
|
|
2790
|
+
detail?: string;
|
|
2791
|
+
revision?: string;
|
|
2792
|
+
}
|
|
2793
|
+
/** An unchanged status is re-sent at most this often (a liveness signal). */
|
|
2794
|
+
declare const STATUS_REPORT_INTERVAL_MS: number;
|
|
2795
|
+
/**
|
|
2796
|
+
* Sends health reports on change, or when the same report is older than
|
|
2797
|
+
* {@link STATUS_REPORT_INTERVAL_MS}. Sends are serialized; a failed send is
|
|
2798
|
+
* not remembered, so the next signal retries. Never throws.
|
|
2799
|
+
*/
|
|
2800
|
+
declare class CredentialStatusReporter {
|
|
2801
|
+
private readonly send;
|
|
2802
|
+
private lastKey;
|
|
2803
|
+
private lastSentAt;
|
|
2804
|
+
private chain;
|
|
2805
|
+
private readonly now;
|
|
2806
|
+
private readonly log;
|
|
2807
|
+
constructor(send: (report: CredentialStatusReport) => Promise<{
|
|
2808
|
+
accepted: boolean;
|
|
2809
|
+
}>, opts: {
|
|
2810
|
+
log: Logger;
|
|
2811
|
+
now?: () => number;
|
|
2812
|
+
});
|
|
2813
|
+
report(report: CredentialStatusReport): Promise<void>;
|
|
2814
|
+
private deliver;
|
|
2815
|
+
}
|
|
2816
|
+
//#endregion
|
|
2478
2817
|
//#region src/host.d.ts
|
|
2479
2818
|
interface ClaudeCodeHostConfig {
|
|
2480
2819
|
/** Chat service WS URL (e.g. wss://chat.dev.alfe.ai/ws). */
|
|
@@ -2492,12 +2831,34 @@ interface ClaudeCodeHostConfig {
|
|
|
2492
2831
|
/**
|
|
2493
2832
|
* Bare Claude model id for `claude -p --model` (e.g. `claude-opus-4-8` or the
|
|
2494
2833
|
* `opus`/`sonnet`/`haiku` aliases). Sourced from the agent's `defaultModel`
|
|
2495
|
-
* via `ALFE_DEFAULT_MODEL`. Omitted → the operator's `claude` CLI default
|
|
2834
|
+
* via `ALFE_DEFAULT_MODEL`. Omitted → the operator's `claude` CLI default on
|
|
2835
|
+
* a credential or local login, `PROXY_DEFAULT_MODEL` on the AI proxy.
|
|
2496
2836
|
* NEVER provider-qualified (`anthropic/…`) — that's an OpenClaw-only shape.
|
|
2497
2837
|
*/
|
|
2498
2838
|
model?: string;
|
|
2839
|
+
/**
|
|
2840
|
+
* Managed VM (`ALFE_MANAGED=1|true`, set by the daemon). Enables Bash. With
|
|
2841
|
+
* no stored credential a managed agent always runs on the Alfe AI proxy (no
|
|
2842
|
+
* local login to fall back to). Self-hosted when false/absent.
|
|
2843
|
+
*/
|
|
2844
|
+
managed?: boolean;
|
|
2845
|
+
/**
|
|
2846
|
+
* The daemon's loopback AI proxy (`ALFE_LOCAL_AI_PROXY_URL`). Defaults to
|
|
2847
|
+
* `DEFAULT_LOCAL_AI_PROXY_URL`.
|
|
2848
|
+
*/
|
|
2849
|
+
localAiProxyUrl?: string;
|
|
2499
2850
|
logger?: Logger;
|
|
2500
2851
|
}
|
|
2852
|
+
declare const CREDENTIAL_INVALID_MESSAGE = "This agent's Claude credential is invalid or expired. Update it in agent settings.";
|
|
2853
|
+
declare const OUT_OF_CREDITS_MESSAGE = "This agent is out of Alfe credits. Add credits in Alfe Billing, or add a Claude credential in agent settings, then resend your message.";
|
|
2854
|
+
declare const USAGE_LIMIT_MESSAGE = "This agent hit an Alfe usage limit. Raise the limit in Alfe or wait for it to reset, then resend your message.";
|
|
2855
|
+
declare const LOCAL_LOGIN_SWITCHED_MESSAGE = "Your machine's Claude login stopped working, so this agent switched to Alfe credits. Please resend your message.";
|
|
2856
|
+
declare const LOCAL_LOGIN_REFUSED_MESSAGE = "Claude refused this machine's claude login (403). Check the account or its organisation policy, or add a Claude credential in agent settings.";
|
|
2857
|
+
declare const MODEL_UNAVAILABLE_MESSAGE = "This agent's model isn't available on this workspace. Choose another Claude model in agent settings, then resend your message.";
|
|
2858
|
+
declare const PROXY_AUTH_FAILED_MESSAGE = "Alfe AI rejected this agent's key. Reconnect the agent (run `alfe setup` on its machine), or add a Claude credential in agent settings.";
|
|
2859
|
+
declare const CREDENTIAL_UNAVAILABLE_MESSAGE = "This agent's Claude credential couldn't be loaded yet. Try again in a moment.";
|
|
2860
|
+
/** How long a turn waits for the start-up credential fetch before failing. */
|
|
2861
|
+
|
|
2501
2862
|
declare class ClaudeCodeHost {
|
|
2502
2863
|
private readonly chat;
|
|
2503
2864
|
/**
|
|
@@ -2521,14 +2882,104 @@ declare class ClaudeCodeHost {
|
|
|
2521
2882
|
private claudeSessionSave;
|
|
2522
2883
|
private stopping;
|
|
2523
2884
|
private stopPromise;
|
|
2885
|
+
/**
|
|
2886
|
+
* Resolves once the first fetch has answered. Null until `start()` (the
|
|
2887
|
+
* direct handleRequest test seam runs on the local login, no wait).
|
|
2888
|
+
*/
|
|
2889
|
+
private credentialReady;
|
|
2890
|
+
private resolveCredentialReady;
|
|
2891
|
+
/** Turns wait for the first fetch only until this time (start + wait). */
|
|
2892
|
+
private credentialDeadline;
|
|
2893
|
+
private credentialLoaded;
|
|
2894
|
+
/** Turns waiting for the credential, before queue admission (chat.abort). */
|
|
2895
|
+
private readonly waitingTurns;
|
|
2896
|
+
private readonly loaderRestartMs;
|
|
2897
|
+
/** How often a fallen-back self-hosted agent re-checks its local login. */
|
|
2898
|
+
private readonly localLoginRecheckMs;
|
|
2899
|
+
private localLoginRecheck;
|
|
2900
|
+
/** In memory only. Never logged, never persisted. */
|
|
2901
|
+
private credential;
|
|
2902
|
+
/**
|
|
2903
|
+
* The auth every new turn runs on, resolved once the credential fetch
|
|
2904
|
+
* answers (see `resolveAuthSource`). Null before that.
|
|
2905
|
+
*/
|
|
2906
|
+
private authSource;
|
|
2907
|
+
private readonly credentialAbort;
|
|
2908
|
+
private readonly reporter;
|
|
2909
|
+
private readonly probe;
|
|
2910
|
+
private readonly credentialWaitMs;
|
|
2911
|
+
private readonly credentialRetry;
|
|
2524
2912
|
constructor(cfg: ClaudeCodeHostConfig, deps?: {
|
|
2525
|
-
/**
|
|
2526
|
-
|
|
2913
|
+
/**
|
|
2914
|
+
* Per-turn driver factory (test seam). Called once per turn (and once
|
|
2915
|
+
* more for a local-login turn re-run on the AI proxy) with its auth.
|
|
2916
|
+
*/
|
|
2917
|
+
makeDriver?: (auth: ChildAuth) => SessionDriver;
|
|
2527
2918
|
chat?: ChatServiceClient;
|
|
2528
2919
|
api?: AgentApiClient;
|
|
2920
|
+
/** Start-up auth check (test seam; default: a minimal `claude -p`). */
|
|
2921
|
+
probe?: (auth: ChildAuth, signal: AbortSignal) => Promise<ProbeOutcome>;
|
|
2922
|
+
credentialWaitMs?: number;
|
|
2923
|
+
/** Delay before restarting a credential loader that threw (default 5 s). */
|
|
2924
|
+
loaderRestartMs?: number;
|
|
2925
|
+
/**
|
|
2926
|
+
* After falling back from a refused local login, re-probe it this often
|
|
2927
|
+
* and switch back when it works (default: the status-report interval).
|
|
2928
|
+
*/
|
|
2929
|
+
localLoginRecheckMs?: number;
|
|
2930
|
+
credentialRetry?: {
|
|
2931
|
+
baseDelayMs?: number;
|
|
2932
|
+
maxDelayMs?: number;
|
|
2933
|
+
};
|
|
2529
2934
|
});
|
|
2530
2935
|
/** Start the chat WS. Non-blocking — the client reconnects internally. */
|
|
2531
2936
|
start(): Promise<void>;
|
|
2937
|
+
/**
|
|
2938
|
+
* Run the fetch + check, restarting it after an unexpected throw so a bug
|
|
2939
|
+
* can never leave the host without a credential until the next restart.
|
|
2940
|
+
*/
|
|
2941
|
+
private runCredentialLoader;
|
|
2942
|
+
private loadCredential;
|
|
2943
|
+
/**
|
|
2944
|
+
* A method, not a property read: `stopping` flips across awaits, which
|
|
2945
|
+
* control-flow narrowing cannot see.
|
|
2946
|
+
*/
|
|
2947
|
+
private isStopping;
|
|
2948
|
+
/** Same reason as `isStopping`: `authSource` can change across an await. */
|
|
2949
|
+
private currentAuthSource;
|
|
2950
|
+
/** The auth a new turn runs on. Local login until the fetch has answered. */
|
|
2951
|
+
private childAuth;
|
|
2952
|
+
/**
|
|
2953
|
+
* A self-hosted agent with no credential whose local login was refused (401
|
|
2954
|
+
* or an explicit auth message, never a 403): run new turns through the Alfe
|
|
2955
|
+
* AI proxy, and re-check the login periodically so a re-login moves the agent
|
|
2956
|
+
* back off Alfe credits. Never for a stored credential (the user chose it; a
|
|
2957
|
+
* refusal there needs their fix) and never on managed.
|
|
2958
|
+
*/
|
|
2959
|
+
private fallBackToProxy;
|
|
2960
|
+
private scheduleLocalLoginRecheck;
|
|
2961
|
+
/** While fallen back: one local-login probe; back to the login when it works. */
|
|
2962
|
+
private recheckLocalLogin;
|
|
2963
|
+
/**
|
|
2964
|
+
* Start-up check: one minimal real call on the resolved source, reported to
|
|
2965
|
+
* the cloud. A refused local login falls back to the proxy and checks that.
|
|
2966
|
+
*/
|
|
2967
|
+
private checkCredential;
|
|
2968
|
+
/** Report the current auth source as working or refused. */
|
|
2969
|
+
private reportStatus;
|
|
2970
|
+
/**
|
|
2971
|
+
* Wait for the first credential answer BEFORE queue admission, so a waiting
|
|
2972
|
+
* turn holds no slot. Bounded by the start-up deadline: once it has passed,
|
|
2973
|
+
* later turns stop waiting until the load completes. Cancelled by
|
|
2974
|
+
* `chat.abort` or host stop through `cancellation`.
|
|
2975
|
+
*/
|
|
2976
|
+
private awaitCredential;
|
|
2977
|
+
/**
|
|
2978
|
+
* Instant credential gate inside the turn (no waiting: `handleAgent` already
|
|
2979
|
+
* waited). Returns a user-facing failure message, or null when the turn may
|
|
2980
|
+
* run. A host driven without `start()` runs on the local login.
|
|
2981
|
+
*/
|
|
2982
|
+
private credentialGateMessage;
|
|
2532
2983
|
/** Stop admission, abort owned children, and give active turns time to settle. */
|
|
2533
2984
|
stop(): Promise<void>;
|
|
2534
2985
|
/**
|
|
@@ -2539,10 +2990,44 @@ declare class ClaudeCodeHost {
|
|
|
2539
2990
|
private handleAgent;
|
|
2540
2991
|
private deliverAgentOutcome;
|
|
2541
2992
|
private runAgentTurn;
|
|
2993
|
+
/**
|
|
2994
|
+
* Settle a failed turn (C3) after storing its message as the assistant's
|
|
2995
|
+
* reply, so the history shows what the user saw. Stored first: a client that
|
|
2996
|
+
* reloads on the failure must find it. Best-effort: a store failure never
|
|
2997
|
+
* changes the outcome.
|
|
2998
|
+
*/
|
|
2999
|
+
private failTurn;
|
|
3000
|
+
/**
|
|
3001
|
+
* Send every message the memory service has not accepted yet. Indices are
|
|
3002
|
+
* the messages' positions in the session file, so they advance across turns
|
|
3003
|
+
* and survive host restarts; the per-conversation `ingestEpoch` tells the
|
|
3004
|
+
* service when that index space restarted. Ingest under the BARE session
|
|
3005
|
+
* id: the same key the session-store filename and the memory backfill use,
|
|
3006
|
+
* so there is one memory lineage.
|
|
3007
|
+
*
|
|
3008
|
+
* Cursor rules:
|
|
3009
|
+
* - success: advance through the batch. If the server trimmed the batch
|
|
3010
|
+
* (`messageCount` < sent) it kept the NEWEST messages and its watermark
|
|
3011
|
+
* moved past the dropped head, so a resend would be filtered anyway;
|
|
3012
|
+
* advance and warn. The byte bounds keep this path unreachable normally.
|
|
3013
|
+
* - non-retryable 4xx (400/413/422): skip only the oldest message, so one
|
|
3014
|
+
* poison message cannot wedge the conversation.
|
|
3015
|
+
* - anything else (429, 5xx, network): leave the cursor; the next turn
|
|
3016
|
+
* resends.
|
|
3017
|
+
*/
|
|
3018
|
+
private ingestPendingMemory;
|
|
3019
|
+
/** Regenerate CLAUDE.md from the workspace persona files. Never fatal. */
|
|
3020
|
+
private syncPersona;
|
|
2542
3021
|
/**
|
|
2543
3022
|
* Run a turn; on a `--resume` failure (stale/missing claude session id) start
|
|
2544
3023
|
* fresh and prepend the last-N stored messages so the model keeps context.
|
|
2545
3024
|
*/
|
|
3025
|
+
/**
|
|
3026
|
+
* Run one turn on `auth` with its own driver, registered as the session's
|
|
3027
|
+
* running turn so `chat.abort` reaches it. Proxy turns always carry a
|
|
3028
|
+
* registry model.
|
|
3029
|
+
*/
|
|
3030
|
+
private runTurnOn;
|
|
2546
3031
|
private runWithResumeFallback;
|
|
2547
3032
|
private forwardEmission;
|
|
2548
3033
|
private handleChatAbort;
|
|
@@ -2559,45 +3044,6 @@ declare class ClaudeCodeHost {
|
|
|
2559
3044
|
/** Strip the `agent:{agentId}:` prefix from a full server session key. */
|
|
2560
3045
|
declare function stripAgentPrefix(sessionKey: string): string;
|
|
2561
3046
|
//#endregion
|
|
2562
|
-
//#region src/child-env.d.ts
|
|
2563
|
-
/**
|
|
2564
|
-
* Child-process environment construction for spawned `claude` CLI processes.
|
|
2565
|
-
*
|
|
2566
|
-
* TWO non-negotiable invariants (Phase 2 plan, audit B2 + the hard
|
|
2567
|
-
* constraints):
|
|
2568
|
-
*
|
|
2569
|
-
* 1. **Scrub `ANTHROPIC_API_KEY` / `ANTHROPIC_BASE_URL` /
|
|
2570
|
-
* `ANTHROPIC_AUTH_TOKEN`.** A self-hosted Mac very often has these set (for
|
|
2571
|
-
* other tooling). If ANY of them reaches `claude`, the CLI silently switches
|
|
2572
|
-
* from the user's Claude subscription (OAuth) to API-key/proxy auth — which
|
|
2573
|
-
* is exactly what this whole runtime exists to avoid (no Agent SDK, no
|
|
2574
|
-
* proxy, subscription only). The break is SILENT: the turn "works" but bills
|
|
2575
|
-
* the wrong plane. So we strip them unconditionally from the child env.
|
|
2576
|
-
*
|
|
2577
|
-
* 2. **Set `ALFE_CLAUDE_BRIDGE=1`.** The Phase-1 CLI hooks
|
|
2578
|
-
* (`alfe claude hook ...` in `packages/cli/src/commands/claude.ts`) check
|
|
2579
|
-
* `process.env.ALFE_CLAUDE_BRIDGE` FIRST and no-op when set, so the host —
|
|
2580
|
-
* not the interactive-session hooks — owns memory recall/capture for bridged
|
|
2581
|
-
* turns. Omitting this double-captures every message. The env var NAME is a
|
|
2582
|
-
* cross-phase contract; do not rename without updating the CLI.
|
|
2583
|
-
*/
|
|
2584
|
-
/** Anthropic env vars that force API-key / proxy auth and MUST be scrubbed. */
|
|
2585
|
-
declare const SCRUBBED_ANTHROPIC_ENV_VARS: readonly ["ANTHROPIC_API_KEY", "ANTHROPIC_BASE_URL", "ANTHROPIC_AUTH_TOKEN"];
|
|
2586
|
-
/** Cross-phase contract marker (see header + packages/cli/src/commands/claude.ts). */
|
|
2587
|
-
declare const BRIDGE_ENV_VAR = "ALFE_CLAUDE_BRIDGE";
|
|
2588
|
-
/**
|
|
2589
|
-
* Build the env handed to a spawned `claude` child. Pure — takes the base env
|
|
2590
|
-
* explicitly so it unit-tests without touching `process.env`.
|
|
2591
|
-
*
|
|
2592
|
-
* - Every scrubbed Anthropic var is DELETED (not blanked) so `claude`'s
|
|
2593
|
-
* env-detection treats it as absent.
|
|
2594
|
-
* - `ALFE_CLAUDE_BRIDGE=1` is set.
|
|
2595
|
-
* - Any caller-supplied `extra` entries are layered last (e.g. a per-turn
|
|
2596
|
-
* marker) but can NEVER re-introduce a scrubbed var — the scrub runs after
|
|
2597
|
-
* the merge as the final gate.
|
|
2598
|
-
*/
|
|
2599
|
-
declare function buildChildEnv(base: NodeJS.ProcessEnv, extra?: Record<string, string>): NodeJS.ProcessEnv;
|
|
2600
|
-
//#endregion
|
|
2601
3047
|
//#region src/session/session-store.d.ts
|
|
2602
3048
|
type StoredMessageComponent = {
|
|
2603
3049
|
type: 'link_button';
|
|
@@ -2629,6 +3075,12 @@ interface ChatMessage {
|
|
|
2629
3075
|
role: 'user' | 'assistant';
|
|
2630
3076
|
content: string;
|
|
2631
3077
|
timestamp: number;
|
|
3078
|
+
/**
|
|
3079
|
+
* `'error'`: the failure message a turn settled with, stored so the history
|
|
3080
|
+
* shows what the user saw. History only: memory ingest and the resume
|
|
3081
|
+
* preamble skip it (it is not something the agent said).
|
|
3082
|
+
*/
|
|
3083
|
+
kind?: 'error';
|
|
2632
3084
|
senderId?: string;
|
|
2633
3085
|
senderName?: string;
|
|
2634
3086
|
components?: StoredMessageComponent[];
|
|
@@ -2664,7 +3116,10 @@ type ChatActivityRecord = {
|
|
|
2664
3116
|
interface SessionData {
|
|
2665
3117
|
sessionId: string;
|
|
2666
3118
|
agentId: string;
|
|
3119
|
+
/** Always `CHAT_SESSION_CHANNEL` for sessions this host writes. */
|
|
2667
3120
|
channel: string;
|
|
3121
|
+
/** The chat surface that opened the conversation (`mobile`, `dashboard`, ...). */
|
|
3122
|
+
clientType?: string;
|
|
2668
3123
|
tenantId?: string;
|
|
2669
3124
|
userId?: string;
|
|
2670
3125
|
createdAt: string;
|
|
@@ -2677,7 +3132,25 @@ interface SessionData {
|
|
|
2677
3132
|
* pre-persistence files.
|
|
2678
3133
|
*/
|
|
2679
3134
|
activity?: ChatActivityRecord[];
|
|
3135
|
+
/**
|
|
3136
|
+
* Alfe memory ingest cursor. Message indices are POSITIONS in `messages`
|
|
3137
|
+
* (append-only, never trimmed), so they are stable across host restarts and
|
|
3138
|
+
* match the index space the memory backfill uses for these files.
|
|
3139
|
+
* `ingestEpoch` is stamped once per conversation lineage (when this file is
|
|
3140
|
+
* created) and tells the memory service the index space restarted, e.g.
|
|
3141
|
+
* after the 30-day cleanup deleted the file and the conversation resumed.
|
|
3142
|
+
* Absent on files written before the cursor existed.
|
|
3143
|
+
*/
|
|
3144
|
+
memory?: SessionMemoryCursor;
|
|
2680
3145
|
}
|
|
3146
|
+
interface SessionMemoryCursor {
|
|
3147
|
+
/** Per-conversation-lineage epoch sent as `ingestEpoch`. */
|
|
3148
|
+
ingestEpoch: number;
|
|
3149
|
+
/** Highest message index the memory service has accepted (-1 = none). */
|
|
3150
|
+
lastIngestedIndex: number;
|
|
3151
|
+
}
|
|
3152
|
+
/** One message as sent to `memoryIngest`. */
|
|
3153
|
+
|
|
2681
3154
|
interface SessionSummary {
|
|
2682
3155
|
sessionId: string;
|
|
2683
3156
|
agentId: string;
|
|
@@ -2689,10 +3162,26 @@ interface SessionSummary {
|
|
|
2689
3162
|
preview?: string;
|
|
2690
3163
|
messageCount: number;
|
|
2691
3164
|
}
|
|
3165
|
+
/**
|
|
3166
|
+
* The channel every chat session is stored on. Every chat client lists with
|
|
3167
|
+
* `sessions.list { channel: 'alfe' }` and openclaw-chat stores `'alfe'`, so any
|
|
3168
|
+
* other value hides the conversation from the rail.
|
|
3169
|
+
*/
|
|
3170
|
+
|
|
2692
3171
|
declare function getSession(sessionId: string): Promise<SessionData | null>;
|
|
2693
3172
|
declare function saveSession(session: SessionData): Promise<void>;
|
|
2694
|
-
declare function createSession(sessionId: string, agentId: string, channel: string, tenantId?: string, userId?: string): Promise<SessionData>;
|
|
2695
|
-
|
|
3173
|
+
declare function createSession(sessionId: string, agentId: string, channel: string, tenantId?: string, userId?: string, clientType?: string): Promise<SessionData>;
|
|
3174
|
+
/**
|
|
3175
|
+
* Append a message. Returns its index (position in `messages`), the stable
|
|
3176
|
+
* memory-ingest index, or -1 when the session does not exist.
|
|
3177
|
+
*/
|
|
3178
|
+
declare function addMessage(sessionId: string, role: 'user' | 'assistant', content: string, senderId?: string, senderName?: string, components?: StoredMessageComponent[], attachments?: StoredAttachment[]): Promise<number>;
|
|
3179
|
+
/**
|
|
3180
|
+
* Store the failure message a turn settled with as the assistant's reply, so
|
|
3181
|
+
* the history shows what the user saw. Returns its index, or -1 when the
|
|
3182
|
+
* session does not exist.
|
|
3183
|
+
*/
|
|
3184
|
+
|
|
2696
3185
|
/**
|
|
2697
3186
|
* Append a turn's terminalized activity records. Called ONCE per turn (from the
|
|
2698
3187
|
* dispatch `finally`) — never per-delta.
|
|
@@ -2712,4 +3201,4 @@ declare function listSessions(filters?: {
|
|
|
2712
3201
|
*/
|
|
2713
3202
|
declare function resolveHostConfig(): ClaudeCodeHostConfig;
|
|
2714
3203
|
//#endregion
|
|
2715
|
-
export { type ActivityEmission, BRIDGE_ENV_VAR, CLAUDE_PERMISSION_MODES, type ChatActivityRecord, type ChatMessage, ClaudeCodeHost, type ClaudeCodeHostConfig, type ClaudePermissionMode, DEFAULT_ALLOWED_TOOLS, DEFAULT_PERMISSION_MODE, type DriverTurnResult, type EndEmission, type MapperEmission, type MapperState, type RunTurnParams, SCRUBBED_ANTHROPIC_ENV_VARS, type SessionData, SessionDriver, type SessionSummary, TERMINATION_GRACE_MS, TURN_TIMEOUT_MS, type TextEmission, type ThinkingActivity, type ToolActivity, WARM_STREAMING_SUPPORTED, addMessage, appendActivity, buildChildEnv, collectTurnActivityRecords, createMapperState, createSession, getSession, listSessions, mapStreamEvent, mapStreamEvents, resolveHostConfig, saveSession, stripAgentPrefix };
|
|
3204
|
+
export { AUTH_PROBE_TIMEOUT_MS, type ActivityEmission, BRIDGE_ENV_VAR, CLAUDE_PERMISSION_MODES, CREDENTIAL_ENV_VAR, CREDENTIAL_INVALID_MESSAGE, CREDENTIAL_UNAVAILABLE_MESSAGE, type ChatActivityRecord, type ChatMessage, type ChildAuth, type ChildCredential, ClaudeCodeHost, type ClaudeCodeHostConfig, type ClaudePermissionMode, type CredentialSource, type CredentialStatusReport, CredentialStatusReporter, DEFAULT_ALLOWED_TOOLS, DEFAULT_LOCAL_AI_PROXY_URL, DEFAULT_PERMISSION_MODE, type DriverTurnResult, type EndEmission, type HostCredential, LOCAL_LOGIN_REFUSED_MESSAGE, LOCAL_LOGIN_SWITCHED_MESSAGE, MANAGED_ALLOWED_TOOLS, MANAGED_DISALLOWED_TOOLS, MODEL_UNAVAILABLE_MESSAGE, type MapperEmission, type MapperState, OUT_OF_CREDITS_MESSAGE, PROXY_AGENT_MODEL_ENV_VARS, PROXY_API_KEY_PLACEHOLDER, PROXY_AUTH_FAILED_MESSAGE, PROXY_DEFAULT_MODEL, PROXY_MODEL_ENV, type ProbeOutcome, type ProxyDenial, type RunTurnParams, SCRUBBED_ANTHROPIC_ENV_VARS, STATUS_REPORT_INTERVAL_MS, type SessionData, SessionDriver, type SessionSummary, TERMINATION_GRACE_MS, TURN_TIMEOUT_MS, type TextEmission, type ThinkingActivity, type ToolActivity, USAGE_LIMIT_MESSAGE, WARM_STREAMING_SUPPORTED, addMessage, appendActivity, buildChildEnv, buildProbeArgs, classifyProxyDenial, collectTurnActivityRecords, createMapperState, createSession, getSession, isAuthFailureText, listSessions, loadCredentialWithRetry, mapStreamEvent, mapStreamEvents, parseProbeOutput, resolveHostConfig, runAuthProbe, saveSession, stripAgentPrefix };
|