-
Notifications
You must be signed in to change notification settings - Fork 0
Add Session TS examples #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,7 @@ Conceptually, `session.state` is a collection (dictionary or Map) holding key-va | |
|
||
* Data is stored as `key: value`. | ||
* **Keys:** Always strings (`str`). Use clear names (e.g., `'departure_city'`, `'user:language_preference'`). | ||
* **Values:** Must be **serializable**. This means they can be easily saved and loaded by the `SessionService`. Stick to basic types in the specific languages (Python/ Java) like strings, numbers, booleans, and simple lists or dictionaries containing *only* these basic types. (See API documentation for precise details). | ||
* **Values:** Must be **serializable**. This means they can be easily saved and loaded by the `SessionService`. Stick to basic types in the specific languages (Python/Java/TypeScript) like strings, numbers, booleans, and simple lists or dictionaries containing *only* these basic types. (See API documentation for precise details). | ||
* **⚠️ Avoid Complex Objects:** **Do not store non-serializable objects** (custom class instances, functions, connections, etc.) directly in the state. Store simple identifiers if needed, and retrieve the complex object elsewhere. | ||
|
||
2. **Mutability: It Changes** | ||
|
@@ -31,7 +31,7 @@ Conceptually, `session.state` is a collection (dictionary or Map) holding key-va | |
* `DatabaseSessionService` / `VertexAiSessionService`: **Persistent.** State is saved reliably. | ||
|
||
!!! Note | ||
The specific parameters or method names for the primitives may vary slightly by SDK language (e.g., `session.state['current_intent'] = 'book_flight'` in Python, `session.state().put("current_intent", "book_flight)` in Java). Refer to the language-specific API documentation for details. | ||
The specific parameters or method names for the primitives may vary slightly by SDK language (e.g., `session.state['current_intent'] = 'book_flight'` in Python, `session.state().put("current_intent", "book_flight")` in Java, or `context.state.set("current_intent", "book_flight")` in TypeScript). Refer to the language-specific API documentation for details. | ||
|
||
### Organizing State with Prefixes: Scope Matters | ||
|
||
|
@@ -81,19 +81,37 @@ To inject a value from the session state, enclose the key of the desired state v | |
|
||
**Example:** | ||
|
||
```python | ||
from google.adk.agents import LlmAgent | ||
=== "Python" | ||
|
||
```python | ||
from google.adk.agents import LlmAgent | ||
|
||
story_generator = LlmAgent( | ||
name="StoryGenerator", | ||
model="gemini-2.0-flash", | ||
instruction="""Write a short story about a cat, focusing on the theme: {topic}.""" | ||
) | ||
|
||
# Assuming session.state['topic'] is set to "friendship", the LLM | ||
# will receive the following instruction: | ||
# "Write a short story about a cat, focusing on the theme: friendship." | ||
``` | ||
|
||
=== "TypeScript" | ||
|
||
story_generator = LlmAgent( | ||
name="StoryGenerator", | ||
model="gemini-2.0-flash", | ||
instruction="""Write a short story about a cat, focusing on the theme: {topic}.""" | ||
) | ||
```typescript | ||
import { LlmAgent } from "@google/adk"; | ||
|
||
# Assuming session.state['topic'] is set to "friendship", the LLM | ||
# will receive the following instruction: | ||
# "Write a short story about a cat, focusing on the theme: friendship." | ||
``` | ||
const storyGenerator = new LlmAgent({ | ||
name: "StoryGenerator", | ||
model: "gemini-2.5-flash", | ||
instruction: "Write a short story about a cat, focusing on the theme: {topic}." | ||
}); | ||
|
||
// Assuming session.state['topic'] is set to "friendship", the LLM | ||
// will receive the following instruction: | ||
// "Write a short story about a cat, focusing on the theme: friendship." | ||
``` | ||
|
||
#### Important Considerations | ||
|
||
|
@@ -128,6 +146,25 @@ The `InstructionProvider` function receives a `ReadonlyContext` object, which yo | |
) | ||
``` | ||
|
||
=== "TypeScript" | ||
|
||
```typescript | ||
import { LlmAgent, ReadonlyContext } from "@google/adk"; | ||
|
||
// This is an InstructionProvider | ||
function myInstructionProvider(context: ReadonlyContext): string { | ||
// You can optionally use the context to build the instruction | ||
// For this example, we'll return a static string with literal braces. | ||
return "This is an instruction with {{literal_braces}} that will not be replaced."; | ||
} | ||
|
||
const agent = new LlmAgent({ | ||
model: "gemini-2.5-flash", | ||
name: "template_helper_agent", | ||
instruction: myInstructionProvider | ||
}); | ||
``` | ||
|
||
If you want to both use an `InstructionProvider` *and* inject state into your instructions, you can use the `inject_session_state` utility function. | ||
|
||
=== "Python" | ||
|
@@ -223,6 +260,57 @@ This is the simplest method for saving an agent's final text response directly i | |
--8<-- "examples/java/snippets/src/main/java/state/GreetingAgentExample.java:full_code" | ||
``` | ||
|
||
=== "TypeScript" | ||
|
||
```typescript | ||
import { LlmAgent, Runner, InMemorySessionService, isFinalResponse } from "@google/adk"; | ||
import { Content } from "@google/genai"; | ||
|
||
// Define agent with outputKey | ||
const greetingAgent = new LlmAgent({ | ||
name: "Greeter", | ||
model: "gemini-2.5-flash", | ||
instruction: "Generate a short, friendly greeting.", | ||
outputKey: "last_greeting" // Save response to state['last_greeting'] | ||
}); | ||
|
||
// --- Setup Runner and Session --- | ||
const appName = "state_app"; | ||
const userId = "user1"; | ||
const sessionId = "session1"; | ||
const sessionService = new InMemorySessionService(); | ||
const runner = new Runner({ | ||
agent: greetingAgent, | ||
appName: appName, | ||
sessionService: sessionService | ||
}); | ||
const session = await sessionService.createSession({ | ||
appName: appName, | ||
userId: userId, | ||
sessionId: sessionId | ||
}); | ||
console.log(`Initial state: ${JSON.stringify(session.state)}`); | ||
|
||
// --- Run the Agent --- | ||
// Runner handles calling appendEvent, which uses the outputKey | ||
// to automatically create the stateDelta. | ||
const userMessage: Content = { parts: [{ text: "Hello" }] }; | ||
for await (const event of runner.run({ | ||
userId: userId, | ||
sessionId: sessionId, | ||
newMessage: userMessage | ||
Comment on lines
+298
to
+301
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
})) { | ||
if (isFinalResponse(event)) { | ||
console.log("Agent responded."); // Response text is also in event.content | ||
} | ||
} | ||
|
||
// --- Check Updated State --- | ||
const updatedSession = await sessionService.getSession({ appName: appName, userId: userId, sessionId: sessionId }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
console.log(`State after agent run: ${JSON.stringify(updatedSession?.state)}`); | ||
// Expected output might include: {"last_greeting":"Hello there! How can I help you today?"} | ||
``` | ||
|
||
Behind the scenes, the `Runner` uses the `output_key` to create the necessary `EventActions` with a `state_delta` and calls `append_event`. | ||
|
||
**2\. The Standard Way: `EventActions.state_delta` (for Complex Updates)** | ||
|
@@ -287,6 +375,64 @@ For more complex scenarios (updating multiple keys, non-string values, specific | |
--8<-- "examples/java/snippets/src/main/java/state/ManualStateUpdateExample.java:full_code" | ||
``` | ||
|
||
=== "TypeScript" | ||
|
||
```typescript | ||
import { InMemorySessionService, createEvent, EventActions } from "@google/adk"; | ||
|
||
// --- Setup --- | ||
const sessionService = new InMemorySessionService(); | ||
const appName = "state_app_manual"; | ||
const userId = "user2"; | ||
const sessionId = "session2"; | ||
const session = await sessionService.createSession({ | ||
appName: appName, | ||
userId: userId, | ||
sessionId: sessionId, | ||
state: { "user:login_count": 0, "task_status": "idle" } | ||
}); | ||
Comment on lines
+388
to
+393
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, we can skip the writing in the |
||
console.log(`Initial state: ${JSON.stringify(session.state)}`); | ||
|
||
// --- Define State Changes --- | ||
const currentTime = Date.now(); | ||
const stateChanges = { | ||
"task_status": "active", // Update session state | ||
"user:login_count": (session.state["user:login_count"] as number || 0) + 1, // Update user state | ||
"user:last_login_ts": currentTime, // Add user state | ||
"temp:validation_needed": true // Add temporary state (will be discarded) | ||
}; | ||
|
||
// --- Create Event with Actions --- | ||
const actionsWithUpdate: EventActions = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we have cc: @cornellgit |
||
stateDelta: stateChanges, | ||
artifactDelta: {}, | ||
requestedAuthConfigs: {}, | ||
requestedToolConfirmations: {}, | ||
}; | ||
// This event might represent an internal system action, not just an agent response | ||
const systemEvent = createEvent({ | ||
invocationId: "inv_login_update", | ||
author: "system", // Or 'agent', 'tool' etc. | ||
actions: actionsWithUpdate, | ||
timestamp: currentTime | ||
// content might be null or represent the action taken | ||
}); | ||
|
||
// --- Append the Event (This updates the state) --- | ||
await sessionService.appendEvent({ session, event: systemEvent }); | ||
console.log("`appendEvent` called with explicit state delta."); | ||
|
||
// --- Check Updated State --- | ||
const updatedSession = await sessionService.getSession({ | ||
appName: appName, | ||
userId: userId, | ||
sessionId: sessionId | ||
}); | ||
Comment on lines
+426
to
+430
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here |
||
console.log(`State after event: ${JSON.stringify(updatedSession?.state)}`); | ||
// Expected: {"user:login_count":1,"task_status":"active","user:last_login_ts":<timestamp>} | ||
// Note: 'temp:validation_needed' is NOT present. | ||
``` | ||
|
||
**3. Via `CallbackContext` or `ToolContext` (Recommended for Callbacks and Tools)** | ||
|
||
Modifying state within agent callbacks (e.g., `on_before_agent_call`, `on_after_agent_call`) or tool functions is best done using the `state` attribute of the `CallbackContext` or `ToolContext` provided to your function. | ||
|
@@ -342,6 +488,28 @@ For more comprehensive details on context objects, refer to the [Context documen | |
} | ||
``` | ||
|
||
=== "TypeScript" | ||
|
||
```typescript | ||
// In an agent callback or tool function | ||
import { CallbackContext } from "@google/adk"; // or ToolContext | ||
|
||
function myCallbackOrToolFunction( | ||
context: CallbackContext, // Or ToolContext | ||
// ... other parameters ... | ||
) { | ||
// Update existing state | ||
const count = context.state.get("user_action_count", 0); | ||
context.state.set("user_action_count", count + 1); | ||
|
||
// Add new state | ||
context.state.set("temp:last_operation_status", "success"); | ||
|
||
// State changes are automatically part of the event's stateDelta | ||
// ... rest of callback/tool logic ... | ||
} | ||
``` | ||
|
||
**What `append_event` Does:** | ||
|
||
* Adds the `Event` to `session.events`. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const session = await sessionService.createSession({ appName, userId, sessionId });