@agentick/core 0.2.1 → 0.3.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 (94) hide show
  1. package/README.md +210 -23
  2. package/dist/.tsbuildinfo.build +1 -1
  3. package/dist/agentick-instance.d.ts.map +1 -1
  4. package/dist/agentick-instance.js +125 -119
  5. package/dist/agentick-instance.js.map +1 -1
  6. package/dist/app/session-store.d.ts +1 -1
  7. package/dist/app/session-store.js +1 -1
  8. package/dist/app/session.d.ts +26 -17
  9. package/dist/app/session.d.ts.map +1 -1
  10. package/dist/app/session.js +220 -202
  11. package/dist/app/session.js.map +1 -1
  12. package/dist/app/types.d.ts +229 -148
  13. package/dist/app/types.d.ts.map +1 -1
  14. package/dist/com/object-model.d.ts +7 -4
  15. package/dist/com/object-model.d.ts.map +1 -1
  16. package/dist/com/object-model.js +13 -4
  17. package/dist/com/object-model.js.map +1 -1
  18. package/dist/compiler/fiber-compiler.d.ts +8 -16
  19. package/dist/compiler/fiber-compiler.d.ts.map +1 -1
  20. package/dist/compiler/fiber-compiler.js +10 -31
  21. package/dist/compiler/fiber-compiler.js.map +1 -1
  22. package/dist/component/component.d.ts +6 -6
  23. package/dist/component/component.d.ts.map +1 -1
  24. package/dist/hooks/com-state.d.ts +14 -1
  25. package/dist/hooks/com-state.d.ts.map +1 -1
  26. package/dist/hooks/com-state.js +28 -2
  27. package/dist/hooks/com-state.js.map +1 -1
  28. package/dist/hooks/context-info.d.ts +2 -35
  29. package/dist/hooks/context-info.d.ts.map +1 -1
  30. package/dist/hooks/context-info.js +8 -0
  31. package/dist/hooks/context-info.js.map +1 -1
  32. package/dist/hooks/context.d.ts +1 -2
  33. package/dist/hooks/context.d.ts.map +1 -1
  34. package/dist/hooks/context.js +1 -2
  35. package/dist/hooks/context.js.map +1 -1
  36. package/dist/hooks/data.d.ts +18 -1
  37. package/dist/hooks/data.d.ts.map +1 -1
  38. package/dist/hooks/data.js +13 -2
  39. package/dist/hooks/data.js.map +1 -1
  40. package/dist/hooks/index.d.ts +5 -3
  41. package/dist/hooks/index.d.ts.map +1 -1
  42. package/dist/hooks/index.js +5 -1
  43. package/dist/hooks/index.js.map +1 -1
  44. package/dist/hooks/resolved.d.ts +2 -0
  45. package/dist/hooks/resolved.d.ts.map +1 -0
  46. package/dist/hooks/resolved.js +6 -0
  47. package/dist/hooks/resolved.js.map +1 -0
  48. package/dist/hooks/runtime-context.d.ts +45 -0
  49. package/dist/hooks/runtime-context.d.ts.map +1 -1
  50. package/dist/hooks/runtime-context.js +35 -0
  51. package/dist/hooks/runtime-context.js.map +1 -1
  52. package/dist/hooks/timeline.d.ts +10 -0
  53. package/dist/hooks/timeline.d.ts.map +1 -0
  54. package/dist/hooks/timeline.js +13 -0
  55. package/dist/hooks/timeline.js.map +1 -0
  56. package/dist/index.d.ts +2 -1
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +8 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/jsx/components/timeline.d.ts.map +1 -1
  61. package/dist/jsx/components/timeline.js +11 -11
  62. package/dist/jsx/components/timeline.js.map +1 -1
  63. package/dist/local-transport.d.ts +31 -0
  64. package/dist/local-transport.d.ts.map +1 -0
  65. package/dist/local-transport.js +119 -0
  66. package/dist/local-transport.js.map +1 -0
  67. package/dist/model/model.d.ts +0 -2
  68. package/dist/model/model.d.ts.map +1 -1
  69. package/dist/model/model.js.map +1 -1
  70. package/dist/procedure/index.d.ts.map +1 -1
  71. package/dist/testing/index.d.ts +2 -0
  72. package/dist/testing/index.d.ts.map +1 -1
  73. package/dist/testing/index.js +2 -0
  74. package/dist/testing/index.js.map +1 -1
  75. package/dist/testing/mock-app.d.ts.map +1 -1
  76. package/dist/testing/mock-app.js +5 -15
  77. package/dist/testing/mock-app.js.map +1 -1
  78. package/dist/testing/mocks.d.ts +2 -3
  79. package/dist/testing/mocks.d.ts.map +1 -1
  80. package/dist/testing/mocks.js +2 -3
  81. package/dist/testing/mocks.js.map +1 -1
  82. package/dist/testing/render-agent.d.ts +1 -1
  83. package/dist/testing/render-agent.d.ts.map +1 -1
  84. package/dist/testing/render-agent.js +5 -5
  85. package/dist/testing/render-agent.js.map +1 -1
  86. package/dist/testing/test-environment.d.ts +122 -0
  87. package/dist/testing/test-environment.d.ts.map +1 -0
  88. package/dist/testing/test-environment.js +126 -0
  89. package/dist/testing/test-environment.js.map +1 -0
  90. package/package.json +2 -2
  91. package/dist/hibernation/index.d.ts +0 -126
  92. package/dist/hibernation/index.d.ts.map +0 -1
  93. package/dist/hibernation/index.js +0 -127
  94. package/dist/hibernation/index.js.map +0 -1
package/README.md CHANGED
@@ -626,6 +626,7 @@ const app = createApp(MyApp, {
626
626
  devTools: true, // Enable DevTools emission
627
627
  tools: [ExternalTool], // Additional tools (merged with JSX <Tool>s)
628
628
  mcpServers: { ... }, // MCP server configs
629
+ environment: myEnv, // Execution environment (see below)
629
630
  });
630
631
  ```
631
632
 
@@ -741,43 +742,139 @@ const DelegateTool = createTool({
741
742
  - **Depth limit**: Maximum 10 levels of nesting (throws if exceeded).
742
743
  - **Cleanup**: Children are removed from `session.children` when they complete.
743
744
 
744
- ### Session Persistence & Hibernation
745
+ ### Session Persistence
745
746
 
746
- Control hibernation, limits, and auto-cleanup:
747
+ Sessions auto-persist after each execution and auto-restore when accessed via `app.session(id)`.
747
748
 
748
749
  ```typescript
749
750
  const app = createApp(MyApp, {
750
751
  model,
751
752
  sessions: {
752
- store: new RedisSessionStore(redis), // Or ":memory:" for SQLite
753
- maxActive: 100, // Max concurrent sessions
754
- idleTimeout: 5 * 60 * 1000, // Hibernate after 5 min idle
755
- autoHibernate: true, // Auto-hibernate on idle
753
+ store: "./data/sessions.db", // SQLite file (or ':memory:', or custom SessionStore)
754
+ maxActive: 100, // Max concurrent in-memory sessions
755
+ idleTimeout: 5 * 60 * 1000, // Evict from memory after 5 min idle
756
756
  },
757
+ });
758
+ ```
757
759
 
758
- // Session lifecycle hooks
759
- onSessionCreate: (session) => {
760
- /* ... */
761
- },
762
- onSessionClose: (sessionId) => {
763
- /* ... */
760
+ **How it works:**
761
+
762
+ 1. After each execution, session state is auto-saved to the store (fire-and-forget — persist failures don't block execution)
763
+ 2. When `app.session("user-123")` is called and the session isn't in memory, it's auto-restored from the store
764
+ 3. `useComState` and `useData` values are included in snapshots by default (set `{ persist: false }` to exclude)
765
+ 4. `maxActive` and `idleTimeout` control memory — evicted sessions can be restored from store
766
+
767
+ #### Snapshot Contents
768
+
769
+ A `SessionSnapshot` captures:
770
+
771
+ | Field | Type | Description |
772
+ | ----------- | --------------------------- | ------------------------------------------------------ |
773
+ | `timeline` | `COMTimelineEntry[] ∣ null` | Full conversation history |
774
+ | `comState` | `Record<string, unknown>` | All `useComState` values (with `persist !== false`) |
775
+ | `dataCache` | `Record<string, ...>` | All `useData` cached values (with `persist !== false`) |
776
+ | `tick` | `number` | Tick count at snapshot time |
777
+ | `usage` | `UsageStats` | Accumulated token usage |
778
+
779
+ #### Lifecycle Hooks
780
+
781
+ ```typescript
782
+ const app = createApp(MyApp, {
783
+ model,
784
+ sessions: { store: "./sessions.db" },
785
+
786
+ // Before save — cancel or modify snapshot
787
+ onBeforePersist: (session, snapshot) => {
788
+ if (snapshot.tick < 2) return false; // Don't persist short sessions
764
789
  },
765
790
 
766
- // Hibernation hooks
767
- onBeforeHibernate: (session, snapshot) => {
768
- // Return false to cancel, modified snapshot, or void
769
- if (session.inspect().lastToolCalls.length > 0) return false;
791
+ // After save
792
+ onAfterPersist: (sessionId, snapshot) => {
793
+ console.log(`Saved session ${sessionId}`);
770
794
  },
771
- onAfterHibernate: (sessionId, snapshot) => {
772
- /* ... */
795
+
796
+ // Before restore — migrate old formats
797
+ onBeforeRestore: (sessionId, snapshot) => {
798
+ if (snapshot.version !== "1.0") return migrateSnapshot(snapshot);
773
799
  },
774
- onBeforeHydrate: (sessionId, snapshot) => {
775
- // Migrate old formats, validate, etc.
800
+
801
+ // After restore
802
+ onAfterRestore: (session, snapshot) => {
803
+ console.log(`Restored session ${session.id} at tick ${snapshot.tick}`);
776
804
  },
777
- onAfterHydrate: (session, snapshot) => {
778
- /* ... */
805
+ });
806
+ ```
807
+
808
+ #### Restore Layers
809
+
810
+ **Layer 1 (default):** Snapshot data is auto-applied. Timeline, comState, and dataCache are restored directly. Components see their previous state via `useComState` and `useData`.
811
+
812
+ **Layer 2 (resolve):** When `resolve` is configured, auto-apply is disabled. Resolve functions control reconstruction and receive the snapshot as context. Results are available via `useResolved(key)`.
813
+
814
+ ```typescript
815
+ const app = createApp(MyApp, {
816
+ model,
817
+ sessions: { store: "./sessions.db" },
818
+
819
+ // Layer 2: resolve controls reconstruction
820
+ resolve: {
821
+ greeting: (ctx) => `Welcome back! You were on tick ${ctx.snapshot?.tick}`,
822
+ userData: async (ctx) => fetchUser(ctx.sessionId),
779
823
  },
780
824
  });
825
+
826
+ // In components:
827
+ function MyAgent() {
828
+ const greeting = useResolved<string>("greeting");
829
+ const userData = useResolved<User>("userData");
830
+ // ...
831
+ }
832
+ ```
833
+
834
+ #### Context Management vs History
835
+
836
+ The session's `_timeline` is the append-only historical log — it grows with every message. The `<Timeline>` component controls what the model _sees_ (context) via its props:
837
+
838
+ ```tsx
839
+ // Full history → model context (default)
840
+ <Timeline />
841
+
842
+ // Only recent messages in context
843
+ <Timeline limit={20} />
844
+
845
+ // Token-budgeted context
846
+ <Timeline maxTokens={8000} strategy="sliding-window" headroom={500} />
847
+
848
+ // Role filtering
849
+ <Timeline roles={['user', 'assistant']} />
850
+ ```
851
+
852
+ The `useTimeline()` hook provides direct access for advanced patterns:
853
+
854
+ ```tsx
855
+ function MyAgent() {
856
+ const timeline = useTimeline();
857
+
858
+ // Read current entries
859
+ console.log(timeline.entries.length);
860
+
861
+ // Replace timeline (e.g., after summarization)
862
+ timeline.set([summaryEntry, ...recentEntries]);
863
+
864
+ // Transform timeline
865
+ timeline.update((entries) => entries.filter((e) => e.message.role !== "system"));
866
+ }
867
+ ```
868
+
869
+ #### `maxTimelineEntries` — OOM Safety Net
870
+
871
+ For long-running sessions, `maxTimelineEntries` prevents unbounded memory growth by trimming the oldest entries after each tick. This is a safety net, not a context management strategy — use `<Timeline>` props for context control.
872
+
873
+ ```typescript
874
+ const app = createApp(MyApp, {
875
+ model,
876
+ maxTimelineEntries: 500, // Keep at most 500 entries in memory
877
+ });
781
878
  ```
782
879
 
783
880
  ### Procedures & Middleware
@@ -862,7 +959,79 @@ const result = await run(<MyApp />, {
862
959
  await run(<Agent query="default" />, { props: { query: "override" }, model, messages });
863
960
  ```
864
961
 
865
- `createApp` takes a component function and returns a reusable app with session management, hibernation, and middleware support.
962
+ `createApp` takes a component function and returns a reusable app with session management, persistence, and middleware support.
963
+
964
+ ## Execution Environments
965
+
966
+ An `ExecutionEnvironment` controls the execution backend — how compiled context reaches the model and how tool calls are routed. The default is the standard model → tool_use protocol. Swap in a different environment to change the entire execution model without touching your agent code.
967
+
968
+ ```tsx
969
+ import { createApp, type ExecutionEnvironment } from "@agentick/core";
970
+
971
+ const replEnvironment: ExecutionEnvironment = {
972
+ name: "repl",
973
+
974
+ // Transform what the model sees — replace tool schemas with prose descriptions,
975
+ // expose a single "execute" tool, restructure sections, anything.
976
+ prepareModelInput(compiled, tools) {
977
+ const commandList = tools
978
+ .map((t) => `- ${t.metadata?.name}: ${t.metadata?.description}`)
979
+ .join("\n");
980
+ return {
981
+ ...compiled,
982
+ tools: [executeToolSchema],
983
+ system: [...compiled.system, { content: `Available commands:\n${commandList}` }],
984
+ };
985
+ },
986
+
987
+ // Route tool calls — intercept "execute" to a sandbox, let others pass through.
988
+ async executeToolCall(call, tool, next) {
989
+ if (call.name === "execute") {
990
+ return sandbox.run(call.input.code);
991
+ }
992
+ return next();
993
+ },
994
+
995
+ // Session lifecycle
996
+ onSessionInit(session) {
997
+ sandbox.create(session.id);
998
+ },
999
+ onDestroy(session) {
1000
+ sandbox.destroy(session.id);
1001
+ },
1002
+ onPersist(session, snapshot) {
1003
+ return { ...snapshot, comState: { ...snapshot.comState, _sandbox: sandbox.state() } };
1004
+ },
1005
+ onRestore(session, snapshot) {
1006
+ sandbox.restore(snapshot.comState._sandbox);
1007
+ },
1008
+ };
1009
+
1010
+ // Same agent, different execution model
1011
+ const app = createApp(MyAgent, { model, environment: replEnvironment });
1012
+ ```
1013
+
1014
+ The agent's JSX — its `<System>`, `<Timeline>`, `<Tool>` components — stays identical. The environment transforms how that compiled context is consumed and how tool calls execute. This means you can build one agent and run it against multiple backends: standard tool_use for production, a sandboxed REPL for code execution, a human-in-the-loop gateway for approval workflows.
1015
+
1016
+ ### Interface
1017
+
1018
+ All methods are optional. Omitted methods use default behavior.
1019
+
1020
+ | Hook | Purpose | Timing |
1021
+ | ------------------- | --------------------------------------------------- | ------------- |
1022
+ | `prepareModelInput` | Transform compiled context before the model sees it | Per tick |
1023
+ | `executeToolCall` | Intercept, transform, or replace tool execution | Per tool call |
1024
+ | `onSessionInit` | Set up per-session resources (sandbox, workspace) | Once |
1025
+ | `onPersist` | Add environment state to session snapshot | Per save |
1026
+ | `onRestore` | Restore environment state from snapshot | Once |
1027
+ | `onDestroy` | Clean up resources | Once |
1028
+
1029
+ ### Use Cases
1030
+
1031
+ - **REPL/Code Execution**: Replace tool schemas with command descriptions, route `execute` calls to a sandboxed runtime, persist sandbox state across sessions.
1032
+ - **Human-in-the-Loop**: Transform tool calls into approval requests, gate execution on human confirmation, log decisions.
1033
+ - **Sandboxing**: Run tools in isolated containers, inject security boundaries, audit tool invocations.
1034
+ - **Testing**: Intercept specific tools to return canned responses, track all lifecycle calls for assertions. See `createTestEnvironment()` in `@agentick/core/testing`.
866
1035
 
867
1036
  ## DevTools Integration
868
1037
 
@@ -889,6 +1058,24 @@ import { enableReactDevTools } from "@agentick/core";
889
1058
  enableReactDevTools(); // Connects to npx react-devtools on port 8097
890
1059
  ```
891
1060
 
1061
+ ## Local Transport
1062
+
1063
+ `createLocalTransport(app)` bridges an in-process `App` to the `ClientTransport` interface. This enables `@agentick/client` (and `@agentick/react` hooks) to work with a local app without any network layer.
1064
+
1065
+ ```typescript
1066
+ import { createApp } from "@agentick/core";
1067
+ import { createLocalTransport } from "@agentick/core";
1068
+ import { createClient } from "@agentick/client";
1069
+
1070
+ const app = createApp(MyAgent, { model });
1071
+ const transport = createLocalTransport(app);
1072
+ const client = createClient({ baseUrl: "local://", transport });
1073
+ ```
1074
+
1075
+ The transport is always "connected" — there's no network. `send()` delegates to `app.send()` and streams `SessionExecutionHandle` events as `TransportEventData`. Used by `@agentick/tui` for local agent mode.
1076
+
1077
+ See [`packages/shared/src/transport.ts`](../shared/src/transport.ts) for the `ClientTransport` interface.
1078
+
892
1079
  ## License
893
1080
 
894
1081
  MIT