@fastagent-sh/fastagent 0.16.1 → 0.17.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.
Files changed (40) hide show
  1. package/dist/channels/agentcore-state.js +7 -0
  2. package/dist/channels/agentcore.js +24 -5
  3. package/dist/channels/control.d.ts +1 -1
  4. package/dist/channels/control.js +5 -1
  5. package/dist/cli/commands/attach.d.ts +29 -1
  6. package/dist/cli/commands/attach.js +76 -4
  7. package/dist/cli/commands/deploy.js +11 -5
  8. package/dist/cli/commands/dev.js +2 -2
  9. package/dist/cli/commands/info.js +2 -2
  10. package/dist/cli/commands/logs.d.ts +6 -0
  11. package/dist/cli/commands/logs.js +27 -0
  12. package/dist/cli/commands/start.js +2 -2
  13. package/dist/cli/program.js +26 -0
  14. package/dist/deploy/agentcore/logs.d.ts +35 -0
  15. package/dist/deploy/agentcore/logs.js +112 -0
  16. package/dist/deploy/agentcore/plan.d.ts +26 -2
  17. package/dist/deploy/agentcore/plan.js +45 -6
  18. package/dist/deploy/container.js +6 -3
  19. package/dist/engines/pi/config.d.ts +1 -1
  20. package/dist/engines/pi/config.js +1 -1
  21. package/dist/engines/pi/create.d.ts +6 -1
  22. package/dist/engines/pi/create.js +16 -19
  23. package/dist/engines/pi/definition.d.ts +15 -0
  24. package/dist/engines/pi/definition.js +22 -1
  25. package/dist/engines/pi/harness.d.ts +12 -28
  26. package/dist/engines/pi/harness.js +21 -71
  27. package/dist/engines/pi/open.d.ts +1 -1
  28. package/dist/engines/pi/open.js +20 -0
  29. package/dist/engines/pi/report.d.ts +16 -0
  30. package/dist/engines/pi/report.js +30 -0
  31. package/dist/engines/pi/session-builder.js +2 -2
  32. package/dist/engines/pi/session-control.d.ts +23 -4
  33. package/dist/engines/pi/session-control.js +159 -27
  34. package/dist/engines/pi/session-settings.d.ts +51 -0
  35. package/dist/engines/pi/session-settings.js +73 -0
  36. package/dist/engines/pi/sessions.d.ts +21 -7
  37. package/dist/engines/pi/sessions.js +43 -0
  38. package/dist/session-remote.js +17 -0
  39. package/dist/session.d.ts +54 -9
  40. package/package.json +1 -1
@@ -65,6 +65,23 @@ export async function connectSessionControl(options) {
65
65
  const capabilities = await get("/control/capabilities");
66
66
  return {
67
67
  capabilities: () => capabilities,
68
+ // NOT prefetched like capabilities: a live definition can grow a skill between calls, so the
69
+ // list is fetched per call. The endpoint is UNCACHED server-side (it re-reads the definition's
70
+ // skills/ per request), which is what keeps it honest about a directory that changes underneath
71
+ // it. A 404 is SKEW, not a fault in the definition: without this the two read identically
72
+ // (uncoded non-2xx), and a client would report "this agent's skills are unreadable" about a
73
+ // serve that simply predates the route.
74
+ async commands() {
75
+ try {
76
+ return await get("/control/commands");
77
+ }
78
+ catch (error) {
79
+ if (error instanceof ControlRequestError && error.status === 404) {
80
+ throw new ControlRequestError(404, "this serve does not implement /control/commands (it predates the route)");
81
+ }
82
+ throw error;
83
+ }
84
+ },
68
85
  state: (session) => get(`/control/state?session=${encodeURIComponent(session)}`),
69
86
  entries: (session, opts) => get(`/control/entries?session=${encodeURIComponent(session)}${opts?.since !== undefined ? `&since=${encodeURIComponent(opts.since)}` : ""}`, PAYLOAD_TIMEOUT_MS),
70
87
  async dispatch(session, command) {
package/dist/session.d.ts CHANGED
@@ -9,6 +9,14 @@
9
9
  import type { Json, Prompt } from "./agent.ts";
10
10
  export interface SessionControl {
11
11
  capabilities(): SessionCapabilities;
12
+ /** The names this agent exposes — what a composer's `/` completion LISTS. A listing, not a
13
+ * dispatch surface: the data plane takes prompts as text, so what typing one means (expanding it,
14
+ * sending "use the X skill", filtering a menu) is the client's business. Sessionless (the
15
+ * definition is a deployment fact) but ASYNC, because a definition is allowed to be live: an
16
+ * implementation that re-reads it per turn must answer from that same read, or the list and the
17
+ * behavior diverge. `[]` is a complete answer, not a missing one; a definition the implementation
18
+ * cannot read at all is a deployment fault and MAY reject. */
19
+ commands(): Promise<AgentCommand[]>;
12
20
  state(session: string): Promise<SessionState>;
13
21
  /** `since` is an APPEND-ORDER position cursor: "every record appended after the one with this
14
22
  * id", regardless of branch structure. Reconstructing the active path in a branched session is
@@ -21,12 +29,17 @@ export interface SessionControl {
21
29
  dispatch(session: string, command: SessionCommand): Promise<SessionResult>;
22
30
  }
23
31
  /**
24
- * Static support declaration, two kinds of flag:
25
- * - COMMAND GATES (`steering`, `followUp`, `manualCompaction`, `modelSelection`, `thinkingLevel`):
32
+ * STATIC support declaration — sessionless, so nothing here may depend on a session. Two kinds of flag:
33
+ * - COMMAND GATES (`steering`, `followUp`, `manualCompaction`, `modelSelection`, `thinkingLevel`,
34
+ * `navigate`):
26
35
  * clients MUST gate dispatch on them; an unsupported command is rejected before acceptance with
27
36
  * {@link UNSUPPORTED_CAPABILITY_CODE}.
28
37
  * - OBSERVATION-QUALITY flags (`toolProgress`, `usage`): whether those events/state fields appear
29
38
  * at all — nothing to dispatch, nothing to reject.
39
+ *
40
+ * `modelSelection` may carry a list because the registry is a deployment fact; thinking levels
41
+ * depend on the session's current model, so they live on {@link SessionState.availableThinkingLevels}.
42
+ *
30
43
  * `state`/`entries`/`events` are mandatory (the reconnect contract) and deliberately absent here.
31
44
  */
32
45
  export interface SessionCapabilities {
@@ -36,12 +49,30 @@ export interface SessionCapabilities {
36
49
  modelSelection: false | {
37
50
  allowedModels: string[];
38
51
  };
39
- thinkingLevel: false | {
40
- allowedLevels: string[];
41
- };
52
+ /** Whether `set_thinking` is servable at all. WHICH levels is per-session — see
53
+ * {@link SessionState.availableThinkingLevels}. */
54
+ thinkingLevel: boolean;
55
+ /** Whether `navigate` is servable at all — `false` both when the engine's sessions are linear and
56
+ * when this deployment has no write path for them; either way the tree the contract publishes
57
+ * (`SessionEntry.parentId` + `SessionEntries.leafEntryId`) is read-only here. Named after its COMMAND, unlike the older gates (`manualCompaction` gates
58
+ * `compact`, `thinkingLevel` gates `set_thinking`): those already force a client to translate,
59
+ * and a gate keyed by the command literal is the only naming a derived map could ever produce. */
60
+ navigate: boolean;
42
61
  toolProgress: boolean;
43
62
  usage: boolean;
44
63
  }
64
+ /**
65
+ * One name a client can offer the user. Field NAMES follow pi's RPC `get_commands` so a client
66
+ * porting from it maps directly; its `sourceInfo` (file provenance) is deliberately not carried, and
67
+ * `source` is a free-form string rather than pi's closed union — which kinds exist is an engine's
68
+ * business ("skill" is the only one fastagent assembles today), and an engine with none answers `[]`
69
+ * rather than the contract enumerating a set it cannot know.
70
+ */
71
+ export interface AgentCommand {
72
+ name: string;
73
+ description?: string;
74
+ source: string;
75
+ }
45
76
  /** Stable `SessionResult.error.code` for a command the implementation does not support. */
46
77
  export declare const UNSUPPORTED_CAPABILITY_CODE = "unsupported_capability";
47
78
  /** Stable `SessionResult.error.code` for a run-modulating command (`steer`/`follow_up`/`abort`)
@@ -79,7 +110,7 @@ export declare const NOTHING_TO_COMPACT_CODE = "nothing_to_compact";
79
110
  * command as-is fails again. (A run registered without modulation controls is a capability
80
111
  * problem, not a run problem, and rejects with {@link UNSUPPORTED_CAPABILITY_CODE}.) */
81
112
  export declare const RUN_COMMAND_FAILED_CODE = "run_command_failed";
82
- /** Six commands; deliberately NO `prompt` — starting work is the data plane's definition. */
113
+ /** Seven commands; deliberately NO `prompt` — starting work is the data plane's definition. */
83
114
  export type SessionCommand = {
84
115
  type: "steer";
85
116
  prompt: Prompt;
@@ -97,6 +128,14 @@ export type SessionCommand = {
97
128
  } | {
98
129
  type: "set_thinking";
99
130
  level: string;
131
+ }
132
+ /** Move the session's active leaf to `targetId`, an existing entry — the write verb for the tree
133
+ * `entries()` already publishes (and how sibling branches come to exist: the next turn hangs off
134
+ * the new leaf). Every entry `entries()` publishes is a legal target; a `targetId` that is not
135
+ * one rejects `invalid_command`. A boundary mutation otherwise: same lease as a run. */
136
+ | {
137
+ type: "navigate";
138
+ targetId: string;
100
139
  };
101
140
  /**
102
141
  * Acceptance is not outcome: `ok: true` means admitted or applied, never that the run ultimately
@@ -125,10 +164,13 @@ export interface SessionState {
125
164
  * compaction happens inside a run's activity window and reports as `running`. */
126
165
  status: "idle" | "running" | "compacting";
127
166
  activeRunId?: string;
128
- /** The session's durable overrides (set_model / set_thinking), read from the record so a
129
- * reconnecting client sees them without scanning entries. Absent = the assembly default. */
167
+ /** What this session will RUN with, not what was recorded: overrides resolved against the
168
+ * deployment (a model the registry lost falls back to the configured one; a level the current
169
+ * model cannot do is clamped). Absent where the implementation exposes no model control. */
130
170
  model?: string;
131
171
  thinkingLevel?: string;
172
+ /** What `set_thinking` accepts for THIS session — re-read after a `set_model`. */
173
+ availableThinkingLevels?: string[];
132
174
  pending: {
133
175
  steering: number;
134
176
  followUp: number;
@@ -222,10 +264,13 @@ export type QueueChangedEvent = SessionEvent<"queue_changed", {
222
264
  runId: string;
223
265
  };
224
266
  /** A boundary mutation changed durable session state (L2; no runId — boundary mutations happen
225
- * between runs). */
267
+ * between runs). `leafEntryId` reports a `navigate` — a deliberate move of the branch head, which
268
+ * a second attached client would otherwise have no signal for. It is NOT a general leaf feed:
269
+ * every turn advances the leaf too, and that is read from `entries()`/`state()` after the run. */
226
270
  export type StateChangedEvent = SessionEvent<"state_changed", {
227
271
  model?: string;
228
272
  thinkingLevel?: string;
273
+ leafEntryId?: string;
229
274
  }>;
230
275
  /** Manual compaction bounds (L2): every `compaction_started` is closed by exactly one
231
276
  * `compaction_finished` — `summary` on success, `error` on failure, `aborted: true` on a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastagent-sh/fastagent",
3
- "version": "0.16.1",
3
+ "version": "0.17.0",
4
4
  "description": "Vibe first. Then FastAgent: turn a local agent directory into a live service in your app, on GitHub, Telegram, Slack, or behind any channel.",
5
5
  "keywords": [
6
6
  "agent",