Skip to content
Merged

Next #431

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
089fa93
chore: initialize branch for issue #414
0xTomDaniel Feb 12, 2026
04141a6
fix(web): add delegation signing fallback for no-caveat guard
0xTomDaniel Feb 12, 2026
03b17f6
Merge pull request #417 from EmberAGI/fix/416-delegation-signing-caveats
0xTomDaniel Feb 12, 2026
ba54c32
fix(agent-pendle): guard background cycle runs until setup complete
0xTomDaniel Feb 12, 2026
0172fb5
Merge pull request #415 from EmberAGI/fix/414-agent-pendle-graph-recu…
0xTomDaniel Feb 12, 2026
122cd93
feat(web-ag-ui): add agent detail links and icon client
Feb 13, 2026
d60db75
feat(web): hide pre-hire metrics panel
Feb 13, 2026
c49b857
feat(web): skeletonize agent stat numbers
Feb 13, 2026
86f2330
feat(web): skeletonize hire agents numbers
Feb 13, 2026
bf95d03
feat(web): improve featured cards with icons + metrics
Feb 13, 2026
e8ddec4
fix(web-ag-ui): stabilize fire + dev stack reset
0xTomDaniel Feb 13, 2026
4259857
refactor(web-ag-ui): rename ClmmTransaction to AgentTransaction
0xTomDaniel Feb 13, 2026
7e103e5
fix(agent-pendle): surface fire unwind tx hashes
0xTomDaniel Feb 13, 2026
261c663
fix(web): tolerate busy thread during agent sync
0xTomDaniel Feb 13, 2026
6480f9f
feat(web): improve hire agents cards and icon loading
Feb 13, 2026
fc3a0aa
test(web): cover hire agents top cards layout
Feb 13, 2026
1c423c5
fix(web-ag-ui): fire completes on interrupt + include approve intents
0xTomDaniel Feb 13, 2026
82b607f
fix(agent-gmx-allora): close position on fire
0xTomDaniel Feb 13, 2026
f2ab5c5
fix(agent-gmx-allora): execute close on fire
0xTomDaniel Feb 13, 2026
b3480e8
fix(agent-gmx-allora): plan-mode fire is successful
0xTomDaniel Feb 13, 2026
0d28362
fix(agent-gmx-allora): default tx mode execute
0xTomDaniel Feb 13, 2026
8259e7f
fix(agent-clmm): unwind on fire + accept null iconUri
0xTomDaniel Feb 13, 2026
ca09ff5
fix(web-ag-ui): harden fire status + gmx close detection
0xTomDaniel Feb 13, 2026
15161c7
fix(ci): exclude web-ag-ui subpackages from typescript build
0xTomDaniel Feb 14, 2026
333c90f
fix(ci): build web-ag-ui via workspace root
0xTomDaniel Feb 14, 2026
627c0f0
fix(web): resolve exhaustive-deps lint in fire hook
0xTomDaniel Feb 14, 2026
100377f
fix(ci): run web-ag-ui lint explicitly
0xTomDaniel Feb 14, 2026
a63e343
fix(web): allow build without Privy env
0xTomDaniel Feb 14, 2026
c4b3b7e
fix(ci): run web-ag-ui build explicitly
0xTomDaniel Feb 14, 2026
7fb220c
fix(agent-pendle): stabilize fetch init typing
0xTomDaniel Feb 14, 2026
44e095d
fix(agent-pendle): avoid fetch typing drift in CI
0xTomDaniel Feb 14, 2026
6b6ab7e
fix(agent-pendle): bypass RequestInit typing drift
0xTomDaniel Feb 14, 2026
0472e29
fix(ci): pin pnpm and freeze lockfile
0xTomDaniel Feb 14, 2026
68de0df
feat(web): polish hire agents visuals + fix icon rendering
Feb 14, 2026
67e3d8b
chore(web): tighten hire-agents typography/spacing
Feb 14, 2026
14b743e
chore(web): refine privy gate banner styling
Feb 14, 2026
5c0e8e0
feat(web): use Ember logo + verified badge for creator
Feb 15, 2026
2c2213a
fix(web): stabilize sidebar width and QA build order
Feb 15, 2026
ea7d904
feat(web): polish agent detail pre-hire hero card
Feb 15, 2026
3e9c259
feat(web): show for-hire detail metrics and enable QA ui preview
Feb 15, 2026
7c4d281
feat(web): align pre-hire agent card + tabs + charts to figma
Feb 15, 2026
32fefdc
feat(web): align prehire details and add mock sparklines
Feb 15, 2026
a8237a4
feat(web): refine hire agents cards and agent detail visuals
Feb 15, 2026
7c66523
feat(web): add agent detail tab preview and icon overflow
Feb 15, 2026
23ce58a
feat(web): unify primary CTA sizing
Feb 15, 2026
541e041
feat(web): restyle transaction history table
Feb 15, 2026
fa70c5a
fix(web): prevent hire crash when agent view is partial
Feb 16, 2026
58aafc7
feat(web): harden icon fidelity and align agent visuals
Feb 16, 2026
4e085cc
feat(web): refine sidebar branding and fix hire-list avatar fit
Feb 16, 2026
2fa0349
feat(web): refine agent UI states and strengthen test coverage
Feb 16, 2026
d397d64
fix(ci): resolve PR-merge build typing drift
0xTomDaniel Feb 16, 2026
e731c4d
Merge pull request #420 from EmberAGI/fix/fire-command-concurrency
0xTomDaniel Feb 16, 2026
647a304
chore(ci): add merge-group trigger and queue runbook
0xTomDaniel Feb 16, 2026
3f71e6c
Merge pull request #424 from EmberAGI/issue/422-merge-context-safety
0xTomDaniel Feb 16, 2026
516674f
Merge branch 'next' into feature/web-ag-visuals-kickoff
0xTomDaniel Feb 16, 2026
df9cac7
Merge pull request #423 from EmberAGI/feature/web-ag-visuals-kickoff
0xTomDaniel Feb 16, 2026
06bc7aa
fix(web): stabilize hire-agent icon rendering and detail route identity
0xTomDaniel Feb 16, 2026
256e1bd
fix: align onboarding steps with dynamic interrupts across agents
0xTomDaniel Feb 16, 2026
5f52616
fix(web-ag-ui): stabilize onboarding delegation lifecycle
0xTomDaniel Feb 17, 2026
c1ff121
fix(agent-workflows): checkpoint onboarding blocked state before inte…
0xTomDaniel Feb 17, 2026
a090464
fix(web-ag-ui): harden onboarding interrupts and cycle routing
0xTomDaniel Feb 17, 2026
caf7b0a
fix(web-ag-ui): keep GMX funding blockers out of failed state
0xTomDaniel Feb 17, 2026
66ce923
fix(ci): align root lockfile patch hash for ag-ui langgraph
0xTomDaniel Feb 17, 2026
5d2bd77
Merge pull request #427 from EmberAGI/chore/finalize-product-qa-426
0xTomDaniel Feb 18, 2026
4832c47
feat(registry): expose lifecycle capability contracts for plugins
0xTomDaniel Feb 19, 2026
d559ff4
refactor(registry): remove graph wording from lifecycle type names
0xTomDaniel Feb 19, 2026
634ba89
Merge pull request #430 from EmberAGI/feature/public-lifecycle-capabi…
0xTomDaniel Feb 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .actrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest
--container-architecture linux/amd64
9 changes: 4 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ on:
push:
branches: [main, master]
pull_request:
paths:
- "typescript/**"
- ".github/workflows/ci.yml"
merge_group:
branches: [main, master, next]
workflow_dispatch:

jobs:
Expand All @@ -25,12 +24,12 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10
version: 10.7.0
run_install: false

- name: Install dependencies in project
working-directory: ./typescript
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile

- name: Run linter
working-directory: ./typescript
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/onchain-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10
version: 10.7.0
run_install: false

- name: Install dependencies in project
working-directory: ./typescript
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
Expand Down
43 changes: 43 additions & 0 deletions docs/merge-queue-runbook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Merge Queue Runbook

## Purpose

This runbook prevents PR-head vs merge-ref drift by enforcing CI in merge context and serializing merges through GitHub merge queue.

## Required repository settings

- `CI` workflow includes `merge_group` trigger.
- Branch rulesets for `next` and default branch require:
- Strict required status checks (`build`).
- Merge queue enabled.

## Daily workflow

1. Open PR as usual and wait for required checks.
2. Resolve review feedback and re-run checks.
3. Use merge queue instead of direct merge.
4. Let queue revalidate in merge context before final merge.

## When to run a local merge-ref check (optional)

Run local parity checks when a PR is high-risk or multiple related PRs are landing together.

Recommended quick check:

```bash
act merge_group -W .github/workflows/ci.yml -n
```

If you suspect integration conflicts, run a local merge-ref simulation and verify lint/build:

```bash
git fetch origin pull/<PR_NUMBER>/head:pr-head pull/<PR_NUMBER>/merge:pr-merge
git diff pr-head..pr-merge -- <path/to/suspect/file>
pnpm -C typescript lint
pnpm -C typescript build
```

## Operational notes

- Keep admin bypasses rare; bypassing queue weakens merge guarantees.
- If queue latency grows, tune merge queue batch settings before disabling protection.
2 changes: 1 addition & 1 deletion typescript/clients/web-ag-ui/apps/agent-clmm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"test": "pnpm test:unit && pnpm test:int && pnpm test:e2e",
"test:unit": "vitest run --config vitest.config.unit.ts",
"test:int": "bash -lc 'ENV_FILE=.env.test; [ -f \"$ENV_FILE\" ] || ENV_FILE=.env.test.example; exec tsx --env-file=\"$ENV_FILE\" ./node_modules/vitest/vitest.mjs run --config vitest.config.int.ts \"$@\"' --",
"test:e2e": "bash -lc 'ENV_FILE=.env.test; [ -f \"$ENV_FILE\" ] || ENV_FILE=.env.test.example; exec tsx --env-file=\"$ENV_FILE\" ./node_modules/vitest/vitest.mjs run --config vitest.config.e2e.ts --no-file-parallelism --maxConcurrency=1 \"$@\"' --",
"test:e2e": "bash -lc 'ENV_FILE=.env.test; [ -f \"$ENV_FILE\" ] || ENV_FILE=.env.test.example; CLMM_E2E=\"${CLMM_E2E:-true}\" LANGGRAPH_DEPLOYMENT_URL=\"${LANGGRAPH_DEPLOYMENT_URL:-http://localhost:8124}\" exec tsx --env-file=\"$ENV_FILE\" ./node_modules/vitest/vitest.mjs run --config vitest.config.e2e.ts --no-file-parallelism --maxConcurrency=1 \"$@\"' --",
"test:watch": "vitest watch",
"test:ci": "pnpm test:unit && pnpm test:int",
"lint": "eslint \"src\" \"tests\" --ext .ts",
Expand Down
18 changes: 15 additions & 3 deletions typescript/clients/web-ag-ui/apps/agent-clmm/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,28 @@ import { extractCommand, resolveCommandTarget, runCommandNode } from './workflow
import { runCycleCommandNode } from './workflow/nodes/runCycleCommand.js';
import { summarizeNode } from './workflow/nodes/summarize.js';
import { syncStateNode } from './workflow/nodes/syncState.js';
import { resolveNextOnboardingNode } from './workflow/onboardingRouting.js';
import { saveBootstrapContext } from './workflow/store.js';

/**
* Routes after bootstrap based on the original command.
* - sync: go to syncState (just return state after bootstrap)
* - hire/cycle: continue to listPools for full setup flow
* - hire/cycle: resume from the next missing onboarding requirement
*/
function resolvePostBootstrap(state: ClmmState): 'listPools' | 'syncState' {
function resolvePostBootstrap(
state: ClmmState,
):
| 'listPools'
| 'collectOperatorInput'
| 'collectFundingTokenInput'
| 'collectDelegations'
| 'prepareOperator'
| 'syncState' {
const command = extractCommand(state.messages) ?? state.view.command;
return command === 'sync' ? 'syncState' : 'listPools';
if (command === 'sync') {
return 'syncState';
}
return resolveNextOnboardingNode(state);
}

const store = new InMemoryStore();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ const EmberPoolTokenSchema = z.object({
symbol: z.string(),
decimals: z.number().int().nonnegative(),
isNative: z.boolean().optional(),
iconUri: z.string().optional(),
// Ember occasionally returns `null` for iconUri; normalize to `undefined` so
// pool listing doesn't fail due to a missing icon.
iconUri: z
.string()
.nullable()
.optional()
.transform((value) => value ?? undefined),
isVetted: z.boolean().optional(),
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { describe, expect, it } from 'vitest';

import { PoolListResponseSchema } from './types.js';

describe('PoolListResponseSchema', () => {
it('accepts null token iconUri from Ember API and normalizes to undefined', () => {
const parsed = PoolListResponseSchema.parse({
liquidityPools: [
{
identifier: { chainId: '42161', address: '0xpool' },
tokens: [
{
tokenUid: { chainId: '42161', address: '0xtoken0' },
name: 'Token0',
symbol: 'T0',
decimals: 18,
iconUri: null,
},
{
tokenUid: { chainId: '42161', address: '0xtoken1' },
name: 'Token1',
symbol: 'T1',
decimals: 18,
},
],
currentPrice: '1',
providerId: 'camelot',
poolName: 'T0/T1',
},
],
});

expect(parsed.liquidityPools[0]?.tokens[0]?.iconUri).toBeUndefined();
});
});

Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export type ClmmActivity = {
events: ClmmEvent[];
};

export type ClmmTransaction = {
export type AgentTransaction = {
cycle: number;
action: string;
txHash?: string;
Expand Down Expand Up @@ -221,7 +221,7 @@ type ClmmViewState = {
profile: ClmmProfile;
activity: ClmmActivity;
metrics: ClmmMetrics;
transactionHistory: ClmmTransaction[];
transactionHistory: AgentTransaction[];
accounting: ClmmAccounting;
delegationsBypassActive?: boolean;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { NavSnapshot, FlowLogEvent } from '../accounting/types.js';
import { resolveStoreHistoryLimit } from '../config/constants.js';
import type { RebalanceTelemetry } from '../domain/types.js';

import type { ClmmTransaction } from './context.js';
import type { AgentTransaction } from './context.js';

const STORE_HISTORY_LIMIT = resolveStoreHistoryLimit();

Expand Down Expand Up @@ -88,7 +88,7 @@ export async function appendTelemetryHistory(params: {

export async function appendTransactionHistory(params: {
threadId?: string;
transactions: ClmmTransaction[];
transactions: AgentTransaction[];
store?: BaseStore;
}): Promise<void> {
await appendHistory({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { copilotkitEmitState } from '@copilotkit/sdk-js/langgraph';
import { Command } from '@langchain/langgraph';
import type { Command } from '@langchain/langgraph';

import { resolvePollIntervalMs, resolveStreamLimit } from '../../config/constants.js';
import { logInfo, type ClmmEvent, type ClmmState, type ClmmUpdate } from '../context.js';
Expand All @@ -15,10 +15,9 @@ export const bootstrapNode = async (

if (state.private.bootstrapped) {
logInfo('Skipping bootstrap; state already initialized for thread', { threadId });
return new Command({
update: {},
goto: 'listPools',
});
// Return a no-op update so the graph's post-bootstrap conditional routing
// decides the next node from current state.
return {};
}

// Note: We don't store client instances in state because LangGraph's checkpointer
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { describe, expect, it } from 'vitest';

import type { ClmmState } from '../context.js';

import { bootstrapNode } from './bootstrap.js';

describe('bootstrapNode', () => {
it('returns a no-op update when the thread is already bootstrapped', async () => {
const state = {
private: {
bootstrapped: true,
},
} as unknown as ClmmState;

const result = await bootstrapNode(state, {
configurable: { thread_id: 'thread-1' },
} as never);

expect(result).toEqual({});
});
});
Loading